/*************************************************** */
/* Rule Set Based Access Control                     */
/* Implementation of ACL data structures             */
/* Author and (c) 1999-2002: Amon Ott <ao@rsbac.org> */
/*                                                   */
/* Last modified: 29/Apr/2002                        */
/*************************************************** */

#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/ext2_fs.h>
#include <asm/uaccess.h>
#include <rsbac/types.h>
#include <rsbac/aci_data_structures.h>
#include <rsbac/acl_data_structures.h>
#include <rsbac/error.h>
#include <rsbac/helpers.h>
#include <rsbac/adf.h>
#include <rsbac/aci.h>
#include <rsbac/acl.h>
#include <rsbac/lists.h>
#include <rsbac/proc_fs.h>
#include <rsbac/getname.h>
#include <rsbac/acl_getname.h>
#include <rsbac/rkmem.h>
#include <rsbac/network.h>
#include <linux/string.h>
#include <linux/smp_lock.h>

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

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

static struct rsbac_acl_device_list_head_t device_list_head;

static        rsbac_list_handle_t          dev_handle = NULL;
static        rsbac_list_handle_t          scd_handle = NULL;
static        rsbac_list_handle_t          group_handle = NULL;
static        rsbac_list_handle_t          gm_handle = NULL;
#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
static        rsbac_list_handle_t          netdev_handle = NULL;
#endif
#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
static        rsbac_list_handle_t          nettemp_nt_handle = NULL;
static        rsbac_list_handle_t          nettemp_handle = NULL;
static        rsbac_list_handle_t          netobj_handle = NULL;
#endif

static        rsbac_list_handle_t          default_fd_handle = NULL;
static        rsbac_list_handle_t          default_dev_handle = NULL;
static        rsbac_list_handle_t          default_ipc_handle = NULL;
static        rsbac_list_handle_t          default_scd_handle = NULL;
static        rsbac_list_handle_t          default_u_handle = NULL;
static        rsbac_list_handle_t          default_p_handle = NULL;
#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
static        rsbac_list_handle_t          default_netdev_handle = NULL;
static        rsbac_acl_rights_vector_t    default_netdev_rights = 0;
#endif
#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
static        rsbac_list_handle_t          default_nettemp_nt_handle = NULL;
static        rsbac_list_handle_t          default_netobj_handle = NULL;
static        rsbac_acl_rights_vector_t    default_nettemp_nt_rights = 0;
static        rsbac_acl_rights_vector_t    default_netobj_rights = 0;
#endif

static        rsbac_acl_group_id_t         group_last_new = 0;

static        rsbac_acl_rights_vector_t    default_fd_rights = 0;
static        rsbac_acl_rights_vector_t    default_dev_rights = 0;
static        rsbac_acl_rights_vector_t    default_ipc_rights = 0;
static        rsbac_acl_rights_vector_t    default_scd_rights = 0;
static        rsbac_acl_rights_vector_t    default_u_rights = 0;
static        rsbac_acl_rights_vector_t    default_p_rights = 0;

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

boolean writable(struct super_block * sb_p);

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

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

static inline int fd_hash(rsbac_inode_nr_t inode)
  {
    return(inode % RSBAC_ACL_NR_FD_LISTS);
  }

static int entry_compare(void * desc1, void * desc2)
  {
    int result;
    struct rsbac_acl_entry_desc_t * i_desc1 = desc1;
    struct rsbac_acl_entry_desc_t * i_desc2 = desc2;

    result = memcmp(&i_desc1->subj_type,
                    &i_desc2->subj_type,
                    sizeof(i_desc1->subj_type));
    if(result)
      return result;
    else
      return memcmp(&i_desc1->subj_id,
                    &i_desc2->subj_id,
                    sizeof(i_desc1->subj_id));
  }

static int dev_compare(void * desc1, void * desc2)
  {
    int result;
    struct rsbac_dev_t * i_desc1 = desc1;
    struct rsbac_dev_t * i_desc2 = desc2;

    result = memcmp(&i_desc1->type,
                    &i_desc2->type,
                    sizeof(i_desc1->type));
    if(result)
      return result;
    else
      return memcmp(&i_desc1->id,
                    &i_desc2->id,
                    sizeof(i_desc1->id));
  }

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
static int netdev_compare(void * desc1, void * desc2)
  {
    return strncmp(desc1,
                   desc2,
                   RSBAC_IFNAMSIZ);
  }
#endif

/* acl_register_fd_lists() */
/* register fd ACL lists for device */

static int acl_register_fd_lists(struct rsbac_acl_device_list_item_t * device_p,
                                 kdev_t kdev)
  {
    char                          * name;
    int                             err = 0;
    int                             tmperr;
    char                            number[10];
    u_int                           file_no;
    struct rsbac_list_lol_info_t lol_info;
    rsbac_acl_rights_vector_t       def_mask=RSBAC_ACL_DEFAULT_FD_MASK;

    if(!device_p)
      return(-RSBAC_EINVALIDPOINTER);
    name = rsbac_kmalloc(RSBAC_MAXNAMELEN);
    if(!name)
      return -RSBAC_ENOMEM;

    /* register all the ACL lists of lists */
    for (file_no = 0; file_no < RSBAC_ACL_NR_FD_LISTS; file_no++)
      {
        /* construct name from base name + number */
        strcpy(name, RSBAC_ACL_FD_FILENAME);
        strcat(name, inttostr(number,file_no) );

        lol_info.version = RSBAC_ACL_FD_LIST_VERSION;
        lol_info.key = RSBAC_ACL_LIST_KEY;
        lol_info.desc_size = sizeof(rsbac_inode_nr_t);
        lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
        lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
        lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
        lol_info.max_age = 0;
        tmperr = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                         &(device_p->handles[file_no]),
                                         lol_info,
                                         RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                         rsbac_list_compare_u32,
                                         entry_compare,
                                         NULL,
                                         NULL,
                                         &def_mask,
                                         NULL,
                                         name,
                                         kdev);
        if(tmperr)
          {
            char * tmp;

            tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN);
            if(tmp)
              {
                printk(KERN_WARNING
                       "acl_register_fd_lists(): registering list %u for device %02u:%02u failed with error %s!\n",
                       file_no,
                       MAJOR(kdev),
                       MINOR(kdev),
                       get_error_name(tmp, tmperr));
                rsbac_kfree(tmp);
              }
            err = tmperr;
          }
      }
    return err;
  }

/* acl_detach_fd_lists() */
/* detach from fd ACL lists for device */

static int acl_detach_fd_lists(struct rsbac_acl_device_list_item_t * device_p)
  {
    char                          * name;
    int                             err = 0;
    int                             tmperr;
    char                            number[10];
    u_int                           file_no;

    if(!device_p)
      return(-RSBAC_EINVALIDPOINTER);
    name = rsbac_kmalloc(RSBAC_MAXNAMELEN);
    if(!name)
      return -RSBAC_ENOMEM;

    /* detach all the ACL lists of lists */
    for (file_no = 0; file_no < RSBAC_ACL_NR_FD_LISTS; file_no++)
      {
        /* construct name from base name + number */
        strcpy(name, RSBAC_ACL_FD_FILENAME);
        strcat(name, inttostr(number,file_no) );

        tmperr = rsbac_list_lol_detach(&device_p->handles[file_no],
                                       RSBAC_ACL_LIST_KEY);
        if(tmperr)
          {
            char * tmp;

            tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN);
            if(tmp)
              {
                printk(KERN_WARNING
                       "acl_detach_fd_lists(): detaching from list %u for device %02u:%02u failed with error %s!\n",
                       file_no,
                       MAJOR(device_p->id),
                       MINOR(device_p->id),
                       get_error_name(tmp, tmperr));
                rsbac_kfree(tmp);
              }
            err = tmperr;
          }
      }
    return err;
  }

/************************************************************************** */
/* The lookup functions return NULL, if the item is not found, and a        */
/* pointer to the item otherwise.                                           */

/* first the device item lookup */
static struct rsbac_acl_device_list_item_t * acl_lookup_device(kdev_t kdev)
    {
      struct rsbac_acl_device_list_item_t  * curr = device_list_head.curr;
      
      /* if there is no current item or it is not the right one, search... */
      if(!curr || (curr->id != kdev) )
        {
          curr = device_list_head.head;
          while (curr && (curr->id != kdev))
            {
              curr = curr->next;
            }
          if (curr)
            device_list_head.curr=curr;
        }
      /* it is the current item -> return it */
      return (curr);
    };

/************************************************************************** */
/* The add_item() functions add an item to the list, set head.curr to it,   */
/* and return a pointer to the item.                                        */
/* These functions will NOT check, if there is already an item under the    */
/* same ID! If this happens, the lookup functions will return the old item! */

/* Create a device item without adding to list. No locking needed. */
static struct rsbac_acl_device_list_item_t 
          * create_device_item(kdev_t kdev)
    {
      struct rsbac_acl_device_list_item_t * new_item_p;

      /* allocate memory for new device, return NULL, if failed */
      if ( !(new_item_p = (struct rsbac_acl_device_list_item_t *)
                    rsbac_kmalloc(sizeof(*new_item_p)) ) )
         return(NULL);

      memset(new_item_p, 0, sizeof(*new_item_p));
      new_item_p->id = kdev;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      new_item_p->mount_count = 1;
#endif
      return(new_item_p);
    };

/* Add an existing device item to list. Locking needed. */
static struct rsbac_acl_device_list_item_t 
          * add_device_item(struct rsbac_acl_device_list_item_t * device_p)
    {
      if (!device_p)
         return(NULL);
         
      /* add new device to device list */
      if (!device_list_head.head)
        { /* first device */
          device_list_head.head=device_p;
          device_list_head.tail=device_p;
          device_list_head.curr=device_p;
          device_list_head.count=1;
          device_p->prev=NULL;
          device_p->next=NULL;
        }  
      else
        { /* there is another device -> hang to tail */
          device_p->prev=device_list_head.tail;
          device_p->next=NULL;
          device_list_head.tail->next=device_p;
          device_list_head.tail=device_p;
          device_list_head.curr=device_p;
          device_list_head.count++;
        };
      return(device_p);
    };

/************************************************************************** */
/* The remove_item() functions remove an item from the list. If this item   */
/* is head, tail or curr, these pointers are set accordingly.               */
/* To speed up removing several subsequent items, curr is set to the next   */
/* item, if possible.                                                       */
/* If the item is not found, nothing is done.                               */

static void clear_device_item(struct rsbac_acl_device_list_item_t * device_p)
  {
    if(!device_p)
      return;

    /* now we can remove the item from memory. This means cleaning up */
    acl_detach_fd_lists(device_p);
    /* OK, lets remove the device item itself */
    rsbac_kfree(device_p);
  }; /* end of clear_device_item() */

static void remove_device_item(kdev_t kdev)
    {
      struct rsbac_acl_device_list_item_t    * item_p;
    
      /* first we must locate the item. */
      if ( (item_p = acl_lookup_device(kdev)) )
        { /* ok, item was found */
          if (device_list_head.head == item_p)  
             { /* item is head */
               if (device_list_head.tail == item_p)
                 { /* item is head and tail = only item -> list will be empty*/
                   device_list_head.head = NULL;
                   device_list_head.tail = NULL;
                 }
               else
                 { /* item is head, but not tail -> next item becomes head */
                   item_p->next->prev = NULL;
                   device_list_head.head = item_p->next;
                 };
             }
          else
             { /* item is not head */
               if (device_list_head.tail == item_p)
                 { /*item is not head, but tail -> previous item becomes tail*/
                   item_p->prev->next = NULL;
                   device_list_head.tail = item_p->prev;
                 }
               else
                 { /* item is neither head nor tail -> item is cut out */
                   item_p->prev->next = item_p->next;
                   item_p->next->prev = item_p->prev;
                 };
             };
             
          /* curr is no longer valid -> reset.                              */
          device_list_head.curr=NULL;
          /* adjust counter */
          device_list_head.count--;
          
          /* now we can remove the item from memory. This means cleaning up */
          /* everything below. */
          clear_device_item(item_p);
        };  /* end of if: item was found */

    }; /* end of remove_device_item() */

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

#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
static int
acl_devices_proc_info(char *buffer, char **start, off_t offset, int length, int dummy)
#else
static int
acl_devices_proc_info(char *buffer, char **start, off_t offset, int length)
#endif
{
  int len = 0;
  off_t pos   = 0;
  off_t begin = 0;
  struct rsbac_acl_device_list_item_t   * device_p;
  u_long dflags;

  if (!rsbac_is_initialized()) return (-ENOSYS);

  len += sprintf(buffer, "%u RSBAC ACL Devices\n-------------------\n",
                 device_list_head.count);

  /* wait for read access to device_list_head */
  rsbac_read_lock(&device_list_head.lock, &dflags);
  /* OK, go on */
  for (device_p = device_list_head.head; device_p; device_p = device_p->next)
    {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      len += sprintf(buffer + len, "%02u:%02u\n",
                     MAJOR(device_p->id), MINOR(device_p->id));
#else
      len += sprintf(buffer + len, "%02u:%02u with mount_count = %u\n",
                     MAJOR(device_p->id), MINOR(device_p->id),
                     device_p->mount_count);
#endif
      pos = begin + len;
      if (pos < offset)
        {
          len = 0;
          begin = pos;
        }
      if (pos > offset+length)
        break;
    }
  
  /* free access to device_list_head */
  rsbac_read_unlock(&device_list_head.lock, &dflags);

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

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
static int
stats_acl_proc_info(char *buffer, char **start, off_t offset, int length, int dummy)
#else
static int
stats_acl_proc_info(char *buffer, char **start, off_t offset, int length)
#endif
{
    u_int len = 0;
    off_t pos   = 0;
    off_t begin = 0;

    u_int                                     item_count = 0;
    u_int                                     member_count = 0;
    u_int                                     tmp_count;
    u_int                                     i;
    u_long dflags;
    struct rsbac_acl_device_list_item_t   * device_p;

    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if (!rsbac_is_initialized)
      {
        printk(KERN_WARNING "stats_acl_proc_info(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_aef_acl)
      printk(KERN_DEBUG "stats_acl_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, "ACL Status\n-----------\n");

    /* protect device list */
    rsbac_read_lock(&device_list_head.lock, &dflags);
    device_p = device_list_head.head;
    while(device_p)
      {
        /* reset counters */
        item_count = 0;
        member_count = 0;
        for(i=0; i<RSBAC_ACL_NR_FD_LISTS; i++)
          {
            tmp_count = rsbac_list_lol_count(device_p->handles[i]);
            if(tmp_count > 0)
              item_count+=tmp_count;
            tmp_count = rsbac_list_lol_all_subcount(device_p->handles[i]);
            if(tmp_count > 0)
              member_count += tmp_count;
          }
        len += sprintf(buffer + len, "device %02u:%02u has %i file ACLs, sum of %i members\n",
                       MAJOR(device_p->id),
                       MINOR(device_p->id),
                       item_count,
                       member_count);
        pos = begin + len;
        if (pos < offset)
          {
            len = 0;
            begin = pos;
          }
        if (pos > offset+length)
          {
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            goto out;
          }
        device_p = device_p->next;
      }
    /* unprotect device list */
    rsbac_read_unlock(&device_list_head.lock, &dflags);

    /* dev list */
    len += sprintf(buffer + len, "%li device ACL items, sum of %li members\n",
                   rsbac_list_lol_count(dev_handle),
                   rsbac_list_lol_all_subcount(dev_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    /* SCD list */
    len += sprintf(buffer + len, "%li scd ACL items, sum of %li members\n",
                   rsbac_list_lol_count(scd_handle),
                   rsbac_list_lol_all_subcount(scd_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    /* netdev list */
    len += sprintf(buffer + len, "%li network device ACL items, sum of %li members\n",
                   rsbac_list_lol_count(netdev_handle),
                   rsbac_list_lol_all_subcount(netdev_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    /* nettemp_nt list */
    len += sprintf(buffer + len, "%li network template NT ACL items, sum of %li members\n",
                   rsbac_list_lol_count(nettemp_nt_handle),
                   rsbac_list_lol_all_subcount(nettemp_nt_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    /* nettemp list */
    len += sprintf(buffer + len, "%li network template ACL items, sum of %li members\n",
                   rsbac_list_lol_count(nettemp_handle),
                   rsbac_list_lol_all_subcount(nettemp_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    /* netobj list */
    len += sprintf(buffer + len, "%li network object ACL items, sum of %li members\n",
                   rsbac_list_lol_count(netobj_handle),
                   rsbac_list_lol_all_subcount(netobj_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
#endif

    len += sprintf(buffer + len, "%li groups, last new is %u\n",
                                   rsbac_list_count(group_handle),
                                   group_last_new);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    /* protect gm list */
    len += sprintf(buffer + len, "%li group member items, sum of %li group memberships\n",
                   rsbac_list_lol_count(gm_handle),
                   rsbac_list_lol_all_subcount(gm_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

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

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
static int
acl_acllist_proc_info(char *buffer, char **start, off_t offset, int length, int dummy)
#else
static int
acl_acllist_proc_info(char *buffer, char **start, off_t offset, int length)
#endif
{
    u_int len = 0;
    off_t pos   = 0;
    off_t begin = 0;

    u_int                              i,j,k;
    char                               tmp1[80], tmp2[80];
    u_int                              count = 0;
    int                                tmp_count;
    int                                tmp_sub_count;
    u_int                              member_count = 0;
    u_long dflags;
    struct rsbac_acl_device_list_item_t * device_p;
    rsbac_inode_nr_t                    * fd_desc_p;
    struct rsbac_dev_t                  * dev_desc_p;
    __u8                                * scd_desc_p;
#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    rsbac_netdev_id_t                   * netdev_desc_p;
#endif
#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    rsbac_net_temp_id_t                 * nettemp_desc_p;
    rsbac_net_obj_id_t                  * netobj_desc_p;
#endif
    struct rsbac_acl_entry_desc_t       * sub_desc_p;
    rsbac_acl_rights_vector_t rights;

    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if (!rsbac_is_initialized)
      {
        printk(KERN_WARNING "acl_acllist_proc_info(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_aef_acl)
      printk(KERN_DEBUG "acl_acllist_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, "ACL Lists\n----------\n");

    len += sprintf(buffer + len,
                   "Default FD ACL:      %li members:",
                   rsbac_list_count(default_fd_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_fd_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }

    /* default_dev list */
    len += sprintf(buffer + len, "\nDefault Device ACL:  %li members:",
                   rsbac_list_count(default_dev_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_dev_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }

    /* default_ipc_list */
    len += sprintf(buffer + len, "\nDefault IPC ACL:     %li members:",
                   rsbac_list_count(default_ipc_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_ipc_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }

    /* default_scd_list */
    len += sprintf(buffer + len, "\nDefault SCD ACL:     %li members:",
                   rsbac_list_count(default_scd_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_scd_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }

    /* default_u_list */
    len += sprintf(buffer + len, "\nDefault User ACL:    %li members:",
                   rsbac_list_count(default_u_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_u_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }

    /* default_p list */
    len += sprintf(buffer + len, "\nDefault Process ACL: %li members:",
                   rsbac_list_count(default_p_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_p_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    /* default_netdev list */
    len += sprintf(buffer + len, "\nDefault Network Device ACL:      %li members:",
                   rsbac_list_count(default_netdev_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_netdev_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    /* default_netdev list */
    len += sprintf(buffer + len, "\nDefault Network Template NT ACL: %li members:",
                   rsbac_list_count(default_nettemp_nt_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_nettemp_nt_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }
    /* default_netobj list */
    len += sprintf(buffer + len, "\nDefault Network Object ACL:      %li members:",
                   rsbac_list_count(default_netobj_handle));
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
    tmp_count = rsbac_list_get_all_desc(default_netobj_handle, (void **) &sub_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            len += sprintf(buffer + len, " %s %u,",
                           get_acl_subject_type_name(tmp1,sub_desc_p[i].subj_type),
                           sub_desc_p[i].subj_id);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(sub_desc_p);
                goto out;
              }
          }
        vfree(sub_desc_p);
      }
#endif

    len += sprintf(buffer + len, "\n\nFile/Dir/Fifo/Symlink ACLs:\n");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    /* protect device list */
    rsbac_read_lock(&device_list_head.lock, &dflags);
    device_p = device_list_head.head;
    while(device_p)
      {
        /* reset counters */
        count = 0;
        member_count = 0;
        len += sprintf(buffer + len, "\nDevice %02u:%02u\n inode  count   mask+members",
                       MAJOR(device_p->id),
                       MINOR(device_p->id));
        pos = begin + len;
        if (pos < offset)
          {
            len = 0;
            begin = pos;
          }
        if (pos > offset+length)
          {
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            goto out;
          }
        for(i=0; i<RSBAC_ACL_NR_FD_LISTS; i++)
          {
            tmp_count = rsbac_list_lol_get_all_desc(device_p->handles[i], (void **) &fd_desc_p);
            if(tmp_count > 0)
              {
                for(j=0; j<tmp_count; j++)
                  {
                    len += sprintf(buffer + len, "\n%6u\t  %li\t",
                                   fd_desc_p[j],
                                   rsbac_list_lol_subcount(device_p->handles[i], &fd_desc_p[j]));
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(fd_desc_p);
                        rsbac_read_unlock(&device_list_head.lock, &dflags);
                        goto out;
                      }
                    if(!rsbac_list_lol_get_data(device_p->handles[i], &fd_desc_p[j], &rights))
                      {
                        len += sprintf(buffer + len, "%s\n\t\t",
                                       u64tostracl(tmp1, rights));
                        pos = begin + len;
                        if (pos < offset)
                          {
                            len = 0;
                            begin = pos;
                          }
                        if (pos > offset+length)
                          {
                            vfree(fd_desc_p);
                            rsbac_read_unlock(&device_list_head.lock, &dflags);
                            goto out;
                          }
                      }

                    tmp_sub_count = rsbac_list_lol_get_all_subdesc(device_p->handles[i], &fd_desc_p[j], (void **) &sub_desc_p);
                    if(tmp_sub_count > 0)
                      {
                        for(k=0; k<tmp_sub_count; k++)
                          {
                            len += sprintf(buffer + len, "%s %u, ",
                                           get_acl_subject_type_name(tmp1, sub_desc_p[k].subj_type),
                                           sub_desc_p[k].subj_id);
                            pos = begin + len;
                            if (pos < offset)
                              {
                                len = 0;
                                begin = pos;
                              }
                            if (pos > offset+length)
                              {
                                vfree(sub_desc_p);
                                vfree(fd_desc_p);
                                rsbac_read_unlock(&device_list_head.lock, &dflags);
                                goto out;
                              }
                          }
                        vfree(sub_desc_p);
                        member_count += tmp_sub_count;
                      }
                  }
                count += tmp_count;
                vfree(fd_desc_p);
              }
          }
        len += sprintf(buffer + len, "\n%u file ACLs, sum of %u members\n",
                       count,member_count);
        pos = begin + len;
        if (pos < offset)
          {
            len = 0;
            begin = pos;
          }
        if (pos > offset+length)
          {
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            goto out;
          }
        device_p = device_p->next;
      }
    /* unprotect device list */
    rsbac_read_unlock(&device_list_head.lock, &dflags);

    /* dev list */
    len += sprintf(buffer + len, "\nDevice ACLs:\ntype+id  count  mask+members");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    member_count = 0;
    tmp_count = rsbac_list_lol_get_all_desc(dev_handle, (void **) &dev_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            if(!rsbac_list_lol_get_data(dev_handle, &dev_desc_p[i], &rights))
              {
                len += sprintf(buffer + len, "\n%c%02u:%02u\t  %3li\t%s\n\t\t",
                               'B' + dev_desc_p[i].type,
                               MAJOR(dev_desc_p[i].id),
                               MINOR(dev_desc_p[i].id),
                               rsbac_list_lol_subcount(dev_handle, &dev_desc_p[i]),
                               u64tostracl(tmp1, rights));
                pos = begin + len;
                if (pos < offset)
                  {
                    len = 0;
                    begin = pos;
                  }
                if (pos > offset+length)
                  {
                    vfree(dev_desc_p);
                    goto out;
                  }
              }
            tmp_sub_count = rsbac_list_lol_get_all_subdesc(dev_handle, &dev_desc_p[i], (void **) &sub_desc_p);
            if(tmp_sub_count > 0)
              {
                for(j=0; j<tmp_sub_count; j++)
                  {
                    len += sprintf(buffer + len, "%s %u, ",
                                   get_acl_subject_type_name(tmp1,sub_desc_p[j].subj_type),
                                   sub_desc_p[j].subj_id);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(sub_desc_p);
                        vfree(dev_desc_p);
                        goto out;
                      }
                  }
                vfree(sub_desc_p);
                member_count += tmp_sub_count;
              }
          }
        vfree(dev_desc_p);
      };
    len += sprintf(buffer + len, "\n\n%i device ACL items, sum of %u members\n",
                   tmp_count, member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    /* scd list */
    member_count = 0;
    len += sprintf(buffer + len, "\nSCD ACLs:\nname             count  mask+members");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    tmp_count = rsbac_list_lol_get_all_desc(scd_handle, (void **) &scd_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            if(!rsbac_list_lol_get_data(scd_handle, &scd_desc_p[i], &rights))
              {
                len += sprintf(buffer + len, "\n%-16s  %3li\t%s\n\t\t\t",
                               get_acl_scd_type_name(tmp1, scd_desc_p[i]),
                               rsbac_list_lol_subcount(scd_handle, &scd_desc_p[i]),
                               u64tostracl(tmp2, rights));
                pos = begin + len;
                if (pos < offset)
                  {
                    len = 0;
                    begin = pos;
                  }
                if (pos > offset+length)
                  {
                    vfree(scd_desc_p);
                    goto out;
                  }
              }
            tmp_sub_count = rsbac_list_lol_get_all_subdesc(scd_handle, &scd_desc_p[i], (void **) &sub_desc_p);
            if(tmp_sub_count > 0)
              {
                for(j=0; j<tmp_sub_count; j++)
                  {
                    len += sprintf(buffer + len, "%s %u, ",
                                   get_acl_subject_type_name(tmp1,sub_desc_p[j].subj_type),
                                   sub_desc_p[j].subj_id);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(sub_desc_p);
                        vfree(scd_desc_p);
                        goto out;
                      }
                  }
                vfree(sub_desc_p);
                member_count += tmp_sub_count;
              }
          }
        vfree(scd_desc_p);
      };
    len += sprintf(buffer + len, "\n\n%u SCD ACL items, sum of %u members\n",
                   tmp_count, member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    /* netdev list */
    len += sprintf(buffer + len, "\nNetwork Device ACLs:\nname\t\t count  mask+members");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    member_count = 0;
    tmp_count = rsbac_list_lol_get_all_desc(netdev_handle, (void **) &netdev_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            if(!rsbac_list_lol_get_data(netdev_handle, &netdev_desc_p[i], &rights))
              {
                len += sprintf(buffer + len, "\n%-16s  %3li\t  %s\n\t\t",
                               netdev_desc_p[i],
                               rsbac_list_lol_subcount(netdev_handle, &netdev_desc_p[i]),
                               u64tostracl(tmp1, rights));
                pos = begin + len;
                if (pos < offset)
                  {
                    len = 0;
                    begin = pos;
                  }
                if (pos > offset+length)
                  {
                    vfree(netdev_desc_p);
                    goto out;
                  }
              }
            tmp_sub_count = rsbac_list_lol_get_all_subdesc(netdev_handle, &netdev_desc_p[i], (void **) &sub_desc_p);
            if(tmp_sub_count > 0)
              {
                for(j=0; j<tmp_sub_count; j++)
                  {
                    len += sprintf(buffer + len, "%s %u, ",
                                   get_acl_subject_type_name(tmp1,sub_desc_p[j].subj_type),
                                   sub_desc_p[j].subj_id);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(sub_desc_p);
                        vfree(netdev_desc_p);
                        goto out;
                      }
                  }
                vfree(sub_desc_p);
                member_count += tmp_sub_count;
              }
          }
        vfree(netdev_desc_p);
      };
    len += sprintf(buffer + len, "\n\n%i network device ACL items, sum of %u members\n",
                   tmp_count, member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    /* nettemp_nt list */
    len += sprintf(buffer + len, "\nNetwork Template NT (template protection) ACLs:\nTemplate   count  mask+members");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    member_count = 0;
    tmp_count = rsbac_list_lol_get_all_desc(nettemp_nt_handle, (void **) &nettemp_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            if(!rsbac_list_lol_get_data(nettemp_nt_handle, &nettemp_desc_p[i], &rights))
              {
                len += sprintf(buffer + len, "\n%10u %3li\t%s\n\t\t",
                               nettemp_desc_p[i],
                               rsbac_list_lol_subcount(nettemp_nt_handle, &nettemp_desc_p[i]),
                               u64tostracl(tmp1, rights));
                pos = begin + len;
                if (pos < offset)
                  {
                    len = 0;
                    begin = pos;
                  }
                if (pos > offset+length)
                  {
                    vfree(nettemp_desc_p);
                    goto out;
                  }
              }
            tmp_sub_count = rsbac_list_lol_get_all_subdesc(nettemp_nt_handle, &nettemp_desc_p[i], (void **) &sub_desc_p);
            if(tmp_sub_count > 0)
              {
                for(j=0; j<tmp_sub_count; j++)
                  {
                    len += sprintf(buffer + len, "%s %u, ",
                                   get_acl_subject_type_name(tmp1,sub_desc_p[j].subj_type),
                                   sub_desc_p[j].subj_id);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(sub_desc_p);
                        vfree(nettemp_desc_p);
                        goto out;
                      }
                  }
                vfree(sub_desc_p);
                member_count += tmp_sub_count;
              }
          }
        vfree(nettemp_desc_p);
      };
    len += sprintf(buffer + len, "\n\n%i network template NT ACL items, sum of %u members\n",
                   tmp_count, member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    /* nettemp list */
    len += sprintf(buffer + len, "\nNetwork Template (netobj protection) ACLs:\nTemplate   count  mask+members");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    member_count = 0;
    tmp_count = rsbac_list_lol_get_all_desc(nettemp_handle, (void **) &nettemp_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            if(!rsbac_list_lol_get_data(nettemp_handle, &nettemp_desc_p[i], &rights))
              {
                len += sprintf(buffer + len, "\n%10u %3li\t%s\n\t\t",
                               nettemp_desc_p[i],
                               rsbac_list_lol_subcount(nettemp_handle, &nettemp_desc_p[i]),
                               u64tostracl(tmp1, rights));
                pos = begin + len;
                if (pos < offset)
                  {
                    len = 0;
                    begin = pos;
                  }
                if (pos > offset+length)
                  {
                    vfree(nettemp_desc_p);
                    goto out;
                  }
              }
            tmp_sub_count = rsbac_list_lol_get_all_subdesc(nettemp_handle, &nettemp_desc_p[i], (void **) &sub_desc_p);
            if(tmp_sub_count > 0)
              {
                for(j=0; j<tmp_sub_count; j++)
                  {
                    len += sprintf(buffer + len, "%s %u, ",
                                   get_acl_subject_type_name(tmp1,sub_desc_p[j].subj_type),
                                   sub_desc_p[j].subj_id);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(sub_desc_p);
                        vfree(nettemp_desc_p);
                        goto out;
                      }
                  }
                vfree(sub_desc_p);
                member_count += tmp_sub_count;
              }
          }
        vfree(nettemp_desc_p);
      };
    len += sprintf(buffer + len, "\n\n%i network template ACL items, sum of %u members\n",
                   tmp_count, member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    /* netobj list */
    len += sprintf(buffer + len, "\nNetwork Object ACLs:\nObject-ID count  mask+members");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

    member_count = 0;
    tmp_count = rsbac_list_lol_get_all_desc(netobj_handle, (void **) &netobj_desc_p);
    if(tmp_count > 0)
      {
        for(i=0; i<tmp_count; i++)
          {
            if(!rsbac_list_lol_get_data(netobj_handle, &netobj_desc_p[i], &rights))
              {
                len += sprintf(buffer + len, "\n%p   %3li\t%s\n\t\t",
                               netobj_desc_p[i],
                               rsbac_list_lol_subcount(netobj_handle, &netobj_desc_p[i]),
                               u64tostracl(tmp1, rights));
                pos = begin + len;
                if (pos < offset)
                  {
                    len = 0;
                    begin = pos;
                  }
                if (pos > offset+length)
                  {
                    vfree(netobj_desc_p);
                    goto out;
                  }
              }
            tmp_sub_count = rsbac_list_lol_get_all_subdesc(netobj_handle, &netobj_desc_p[i], (void **) &sub_desc_p);
            if(tmp_sub_count > 0)
              {
                for(j=0; j<tmp_sub_count; j++)
                  {
                    len += sprintf(buffer + len, "%s %u, ",
                                   get_acl_subject_type_name(tmp1,sub_desc_p[j].subj_type),
                                   sub_desc_p[j].subj_id);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(sub_desc_p);
                        vfree(netobj_desc_p);
                        goto out;
                      }
                  }
                vfree(sub_desc_p);
                member_count += tmp_sub_count;
              }
          }
        vfree(netobj_desc_p);
      };
    len += sprintf(buffer + len, "\n\n%i network object ACL items, sum of %u members\n",
                   tmp_count, member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;
#endif

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

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
static int
acl_grouplist_proc_info(char *buffer, char **start, off_t offset, int length, int dummy)
#else
static int
acl_grouplist_proc_info(char *buffer, char **start, off_t offset, int length)
#endif
{
    u_int len = 0;
    off_t pos   = 0;
    off_t begin = 0;

    char                               type;
    int                                count, sub_count;
    int                                i,j;
    u_int                              member_count = 0;
    struct rsbac_acl_group_entry_t * entry_p;
    rsbac_uid_t * user_p;
    rsbac_acl_group_id_t * group_p;
    rsbac_time_t * ttl_p;

    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if (!rsbac_is_initialized)
      {
        printk(KERN_WARNING "acl_grouplist_proc_info(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_aef_acl)
      printk(KERN_DEBUG "acl_grouplist_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, "ACL Groups\n----------\n");

    /* group list */
    len += sprintf(buffer + len, "Group list:  %li groups, last new is %u\nID\ttype name\t\towner\n",
                                 rsbac_list_count(group_handle), group_last_new);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      {
        goto out;
      }

    count = rsbac_list_get_all_data(group_handle, (void **) &entry_p);
    if(count > 0)
      {
        for(i=0; i<count; i++)
          {
            if(entry_p[i].type == ACLG_GLOBAL)
              type = 'G';
            else
              type = 'P';
            len += sprintf(buffer + len, "%u\t%c    %-18s %u\n",
                           entry_p[i].id,
                           type,
                           entry_p[i].name,
                           entry_p[i].owner);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(entry_p);
                goto out;
              }
          }
        vfree(entry_p);
      }

    /* group member list */
    member_count = 0;
    len += sprintf(buffer + len, "\nGroup memberships:\nuser   count\tgroups");
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      {
        goto out;
      }

    count = rsbac_list_lol_get_all_desc(gm_handle, (void **) &user_p);
    if(count > 0)
      {
        for(i=0; i<count; i++)
          {
            sub_count = rsbac_list_lol_get_all_subdesc_ttl(gm_handle,
                                                           &user_p[i],
                                                           (void **) &group_p,
                                                           &ttl_p);
            len += sprintf(buffer + len, "\n%u\t%i\t",
                           user_p[i],
                           sub_count);
            pos = begin + len;
            if (pos < offset)
              {
                len = 0;
                begin = pos;
              }
            if (pos > offset+length)
              {
                vfree(user_p);
                goto out;
              }

            if(sub_count > 0)
              {
                for(j=0; j<sub_count; j++)
                  {
                    if(ttl_p[j])
                      len += sprintf(buffer + len, "%u(ttl:%i) ",
                                     group_p[j], ttl_p[j]);
                    else
                      len += sprintf(buffer + len, "%u ",
                                     group_p[j]);
                    pos = begin + len;
                    if (pos < offset)
                      {
                        len = 0;
                        begin = pos;
                      }
                    if (pos > offset+length)
                      {
                        vfree(group_p);
                        vfree(user_p);
                        goto out;
                      }
                  }
                member_count+=sub_count;
                vfree(group_p);
                vfree(ttl_p);
              }
          }
        vfree(user_p);
      }
    len += sprintf(buffer + len, "\n\n%u user items, sum of %u memberships\n",
                   count,member_count);
    pos = begin + len;
    if (pos < offset)
      {
        len = 0;
        begin = pos;
      }
    if (pos > offset+length)
      goto out;

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 ACL data structures. After this call, all ACL    */
/* data is kept in memory for performance reasons, but is written to disk   */
/* on every change. */

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

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

/* Because there can be no access to aci data structures before init, */
/* rsbac_init_acl() will initialize all rw-spinlocks to unlocked. */

int __init rsbac_init_acl(void)
  {
    int  err = 0;
    struct rsbac_acl_device_list_item_t * device_p = NULL;
    char tmp[80];
    u_long flags;
    struct proc_dir_entry * tmp_entry_p;
    struct rsbac_list_lol_info_t lol_info;
    struct rsbac_list_info_t     list_info;
    rsbac_acl_rights_vector_t    def_mask;

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

    /* set rw-spinlocks to unlocked status and init data structures */
    printk(KERN_INFO "rsbac_init_acl(): Initializing RSBAC: ACL subsystem\n");

    /* Init device list */
    device_list_head.lock = RW_LOCK_UNLOCKED;
    device_list_head.head  = NULL;
    device_list_head.tail  = NULL;
    device_list_head.curr  = NULL;
    device_list_head.count = 0;

    /* register ACL lists */
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_ds_acl)
      printk(KERN_DEBUG "rsbac_init_acl(): Registering lists\n");
#endif
    device_p = create_device_item(rsbac_root_dev);
    if (!device_p)
      {
        printk(KERN_CRIT "rsbac_init_acl(): Could not create device!\n");
        return(-RSBAC_ECOULDNOTADDDEVICE);
      }
    if((err = acl_register_fd_lists(device_p,rsbac_root_dev)))
      printk(KERN_WARNING
             "rsbac_init_acl(): File/Dir ACL registration failed for dev %02u:%02u, err %s!\n",
             MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev), get_error_name(tmp,err));
    /* wait for write access to device_list_head */
    rsbac_write_lock(&device_list_head.lock, &flags);
    device_p = add_device_item(device_p);
    /* device was added, allow access */
    rsbac_write_unlock(&device_list_head.lock, &flags);
    if (!device_p)
      {
        printk(KERN_CRIT "rsbac_init_acl(): Could not add device!\n");
        return(-RSBAC_ECOULDNOTADDDEVICE);
      }

    list_info.version = RSBAC_ACL_DEF_FD_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_fd_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_FD_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default fd");
      }
    if(!rsbac_list_count(default_fd_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_FD_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_FD_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_FD_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): File/Dir default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_fd_handle, &desc, &acman_entry.rights);
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_fd_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_fd_handle, &desc, &gen_entry.rights);
      }

    lol_info.version = RSBAC_ACL_DEV_LIST_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(struct rsbac_dev_t);
    lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
    lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    lol_info.max_age = 0;
    def_mask=RSBAC_ACL_DEFAULT_DEV_MASK;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &dev_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_ACL_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                  dev_compare,
                                  entry_compare,
                                  NULL,
                                  NULL,
                                  &def_mask,
                                  NULL,
                                  RSBAC_ACL_DEV_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "dev");
      }
    list_info.version = RSBAC_ACL_DEF_DEV_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_dev_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_DEV_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default dev");
      }
    if(!rsbac_list_count(default_dev_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_DEV_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_DEV_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_DEV_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): Device default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_dev_handle, &desc, &acman_entry.rights);
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_dev_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_dev_handle, &desc, &gen_entry.rights);
      }

    list_info.version = RSBAC_ACL_DEF_IPC_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_ipc_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_IPC_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default ipc");
      }
    if(!rsbac_list_count(default_ipc_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_IPC_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_IPC_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_IPC_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): IPC default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_ipc_handle, &desc, &acman_entry.rights);
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_ipc_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_ipc_handle, &desc, &gen_entry.rights);
      }

    lol_info.version = RSBAC_ACL_SCD_LIST_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(__u8);
    lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
    lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    lol_info.max_age = 0;
    def_mask=RSBAC_ACL_DEFAULT_SCD_MASK;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &scd_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_ACL_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                  NULL,
                                  entry_compare,
                                  NULL,
                                  NULL,
                                  &def_mask,
                                  NULL,
                                  RSBAC_ACL_SCD_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "scd");
      }
    if(!rsbac_list_lol_count(scd_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_SCD_MASK;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_SCD_ENTRY;
        #ifdef CONFIG_RSBAC_USER_MOD_IOPERM
        struct rsbac_acl_entry_t gen_ioports_entry = RSBAC_ACL_GENERAL_SCD_IOPORTS_ENTRY;
        #endif
        struct rsbac_acl_entry_t gen_other_entry = RSBAC_ACL_GENERAL_SCD_OTHER_ENTRY;
        struct rsbac_acl_entry_t gen_network_entry = RSBAC_ACL_GENERAL_SCD_NETWORK_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_SCD_ENTRY;
        struct rsbac_acl_entry_t sysadm_other_entry = RSBAC_ACL_SYSADM_SCD_OTHER_ENTRY;
        #ifdef CONFIG_RSBAC_USER_MOD_IOPERM
        struct rsbac_acl_entry_t sysadm_kmem_entry = RSBAC_ACL_SYSADM_SCD_KMEM_ENTRY;
        #endif
        struct rsbac_acl_entry_t acman_other_entry = RSBAC_ACL_ACMAN_SCD_OTHER_ENTRY;
        enum  rsbac_acl_scd_type_t scd;

        printk(KERN_WARNING
               "rsbac_init_acl(): SCD ACLs empty on dev %02u:%02u, generating standard entries!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        scd = ST_rlimit;
        if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
          {
            desc.subj_type = gen_entry.subj_type;
            desc.subj_id = gen_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &gen_entry.rights);
          }
        for(scd=ST_time_strucs; scd<=ST_rsbac; scd++)
          {
            if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
              {
                desc.subj_type = sysadm_entry.subj_type;
                desc.subj_id = sysadm_entry.subj_id;
                rsbac_list_lol_subadd(scd_handle, &scd, &desc, &sysadm_entry.rights);
              }
          }
        scd=ST_network;
        if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
          {
            desc.subj_type = sysadm_entry.subj_type;
            desc.subj_id = sysadm_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &sysadm_entry.rights);
            desc.subj_type = gen_network_entry.subj_type;
            desc.subj_id = gen_network_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &gen_network_entry.rights);
          }
        scd=ST_firewall;
        if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
          {
            desc.subj_type = sysadm_entry.subj_type;
            desc.subj_id = sysadm_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &sysadm_entry.rights);
            desc.subj_type = gen_network_entry.subj_type;
            desc.subj_id = gen_network_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &gen_network_entry.rights);
          }
        #ifdef CONFIG_RSBAC_USER_MOD_IOPERM
        scd = ST_ioports;
        if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
          {
            desc.subj_type = gen_ioports_entry.subj_type;
            desc.subj_id = gen_ioports_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &gen_ioports_entry.rights);
          }
        scd = ST_kmem;
        if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
          {
            desc.subj_type = sysadm_kmem_entry.subj_type;
            desc.subj_id = sysadm_kmem_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &sysadm_kmem_entry.rights);
          }
        #endif

        scd = ST_other;
        if(!rsbac_list_lol_add(scd_handle, &scd, &mask))
          {
            desc.subj_type = sysadm_other_entry.subj_type;
            desc.subj_id = sysadm_other_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &sysadm_other_entry.rights);
            desc.subj_type = acman_other_entry.subj_type;
            desc.subj_id = acman_other_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &acman_other_entry.rights);
            desc.subj_type = gen_other_entry.subj_type;
            desc.subj_id = gen_other_entry.subj_id;
            rsbac_list_lol_subadd(scd_handle, &scd, &desc, &gen_other_entry.rights);
          }
      }

    list_info.version = RSBAC_ACL_DEF_SCD_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_scd_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_SCD_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default scd");
      }
    if(!rsbac_list_count(default_scd_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_SCD_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): SCD default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_scd_handle, &desc, &acman_entry.rights);
      }

    list_info.version = RSBAC_ACL_DEF_U_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_u_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_U_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default user");
      }
    if(!rsbac_list_count(default_u_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_U_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_U_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): User default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_u_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_u_handle, &desc, &acman_entry.rights);
      }

    list_info.version = RSBAC_ACL_DEF_P_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_p_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_P_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default process");
      }
    if(!rsbac_list_count(default_p_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_P_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_P_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_P_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): Process default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_p_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_p_handle, &desc, &acman_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_p_handle, &desc, &gen_entry.rights);
      }

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    lol_info.version = RSBAC_ACL_NETDEV_LIST_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_netdev_id_t);
    lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
    lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    lol_info.max_age = 0;
    def_mask=RSBAC_ACL_DEFAULT_NETDEV_MASK;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &netdev_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_ACL_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST | RSBAC_LIST_DEF_DATA,
                                  netdev_compare,
                                  entry_compare,
                                  NULL,
                                  NULL,
                                  &def_mask,
                                  NULL,
                                  RSBAC_ACL_NETDEV_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "netdev");
      }
    list_info.version = RSBAC_ACL_DEF_NETDEV_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_netdev_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_NETDEV_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default netdev");
      }
    if(!rsbac_list_count(default_netdev_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_NETDEV_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_NETDEV_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_NETDEV_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): Network Device default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_netdev_handle, &desc, &acman_entry.rights);
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_netdev_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_netdev_handle, &desc, &gen_entry.rights);
      }
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    lol_info.version = RSBAC_ACL_NETTEMP_NT_LIST_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_net_temp_id_t);
    lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
    lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    lol_info.max_age = 0;
    def_mask=RSBAC_ACL_DEFAULT_NETTEMP_MASK;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &nettemp_nt_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_ACL_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST,
                                  rsbac_list_compare_u32,
                                  entry_compare,
                                  NULL,
                                  NULL,
                                  &def_mask,
                                  NULL,
                                  RSBAC_ACL_NETTEMP_NT_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "nettemp_nt");
      }
    list_info.version = RSBAC_ACL_DEF_NETTEMP_NT_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_nettemp_nt_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_NETTEMP_NT_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default nettemp_nt");
      }
    if(!rsbac_list_count(default_nettemp_nt_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_NETTEMP_NT_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_NETTEMP_NT_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_NETTEMP_NT_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): Network Template NT (template protection) default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_nettemp_nt_handle, &desc, &acman_entry.rights);
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_nettemp_nt_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_nettemp_nt_handle, &desc, &gen_entry.rights);
      }
    lol_info.version = RSBAC_ACL_NETTEMP_LIST_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_net_temp_id_t);
    lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
    lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    lol_info.max_age = 0;
    def_mask=RSBAC_ACL_DEFAULT_NETOBJ_MASK;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &nettemp_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_ACL_BACKUP)
                                  RSBAC_LIST_BACKUP |
                                  #endif
                                  RSBAC_LIST_PERSIST,
                                  rsbac_list_compare_u32,
                                  entry_compare,
                                  NULL,
                                  NULL,
                                  &def_mask,
                                  NULL,
                                  RSBAC_ACL_NETTEMP_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "nettemp");
      }
    lol_info.version = RSBAC_ACL_NETOBJ_LIST_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_net_obj_id_t);
    lol_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* mask */
    lol_info.subdesc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    lol_info.subdata_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    lol_info.max_age = 0;
    def_mask=RSBAC_ACL_DEFAULT_NETOBJ_MASK;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &netobj_handle,
                                  lol_info,
                                  0,
                                  rsbac_list_compare_u32,
                                  entry_compare,
                                  NULL,
                                  NULL,
                                  &def_mask,
                                  NULL,
                                  RSBAC_ACL_NETOBJ_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "netobj");
      }
    list_info.version = RSBAC_ACL_DEF_NETOBJ_LIST_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(struct rsbac_acl_entry_desc_t); /* subj_type + subj_id */
    list_info.data_size = sizeof(rsbac_acl_rights_vector_t); /* rights */
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &default_netobj_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              entry_compare,
                              NULL,
                              NULL,
                              RSBAC_ACL_DEF_NETOBJ_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "default netobj");
      }
    if(!rsbac_list_count(default_netobj_handle))
      {
        struct rsbac_acl_entry_desc_t desc;
        struct rsbac_acl_entry_t acman_entry = RSBAC_ACL_ACMAN_NETOBJ_ENTRY;
        struct rsbac_acl_entry_t sysadm_entry = RSBAC_ACL_SYSADM_NETOBJ_ENTRY;
        struct rsbac_acl_entry_t gen_entry = RSBAC_ACL_GENERAL_NETOBJ_ENTRY;

        printk(KERN_WARNING
               "rsbac_init_acl(): Network Object default ACL empty on dev %02u:%02u, generating standard ACL!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
        desc.subj_type = acman_entry.subj_type;
        desc.subj_id = acman_entry.subj_id;
        rsbac_list_add(default_netobj_handle, &desc, &acman_entry.rights);
        desc.subj_type = sysadm_entry.subj_type;
        desc.subj_id = sysadm_entry.subj_id;
        rsbac_list_add(default_netobj_handle, &desc, &sysadm_entry.rights);
        desc.subj_type = gen_entry.subj_type;
        desc.subj_id = gen_entry.subj_id;
        rsbac_list_add(default_netobj_handle, &desc, &gen_entry.rights);
      }
#endif /* NET_OBJ_PROT */

    /* groups */
    list_info.version = RSBAC_ACL_GROUP_VERSION;
    list_info.key = RSBAC_ACL_LIST_KEY;
    list_info.desc_size = sizeof(rsbac_acl_group_id_t);
    list_info.data_size = sizeof(struct rsbac_acl_group_entry_t);
    list_info.max_age = 0;
    err = rsbac_list_register(RSBAC_LIST_VERSION,
                              &group_handle,
                              list_info,
                              #if defined(CONFIG_RSBAC_ACL_BACKUP)
                              RSBAC_LIST_BACKUP |
                              #endif
                              RSBAC_LIST_PERSIST,
                              rsbac_list_compare_u32,
                              NULL,
                              NULL,
                              RSBAC_ACL_GROUP_FILENAME,
                              0);
    if(err)
      {
        registration_error(err, "group");
      }
    if(!rsbac_list_count(group_handle))
      {
        printk(KERN_WARNING
               "rsbac_init_acl(): Group list empty on dev %02u:%02u!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
      }
    else
      {
        rsbac_list_get_max_desc(group_handle, &group_last_new);
      }

    /* group memberships */
    lol_info.version = RSBAC_ACL_GM_VERSION;
    lol_info.key = RSBAC_ACL_LIST_KEY;
    lol_info.desc_size = sizeof(rsbac_uid_t);
    lol_info.data_size = 0;
    lol_info.subdesc_size = sizeof(rsbac_acl_group_id_t);
    lol_info.subdata_size = 0;
    lol_info.max_age = 0;
    err = rsbac_list_lol_register(RSBAC_LIST_VERSION,
                                  &gm_handle,
                                  lol_info,
                                  #if defined(CONFIG_RSBAC_ACL_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_ACL_GM_FILENAME,
                                  0);
    if(err)
      {
        registration_error(err, "gm");
      }
    if(!rsbac_list_lol_count(gm_handle))
      {
        printk(KERN_WARNING
               "rsbac_init_acl(): Group membership list empty on dev %02u:%02u!\n",
               MAJOR(rsbac_root_dev), MINOR(rsbac_root_dev));
      }

    #if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
    tmp_entry_p = create_proc_entry("acl_devices",
                                    S_IFREG | S_IRUGO,
                                    proc_rsbac_root_p);
    if(tmp_entry_p)
      {
        tmp_entry_p->get_info = acl_devices_proc_info;
      }
    tmp_entry_p = create_proc_entry("stats_acl",
                                    S_IFREG | S_IRUGO,
                                    proc_rsbac_root_p);
    if(tmp_entry_p)
      {
        tmp_entry_p->get_info = stats_acl_proc_info;
      }
    tmp_entry_p = create_proc_entry("acl_acllist",
                                    S_IFREG | S_IRUGO,
                                    proc_rsbac_root_p);
    if(tmp_entry_p)
      {
        tmp_entry_p->get_info = acl_acllist_proc_info;
      }
    tmp_entry_p = create_proc_entry("acl_grouplist",
                                    S_IFREG | S_IRUGO,
                                    proc_rsbac_root_p);
    if(tmp_entry_p)
      {
        tmp_entry_p->get_info = acl_grouplist_proc_info;
      }
    #endif

#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_ds_acl)
      printk(KERN_DEBUG "rsbac_init_acl(): Ready.\n");
#endif
    return(err);
  };

int rsbac_mount_acl(kdev_t kdev)
  {
    int err = 0;
    struct rsbac_acl_device_list_item_t * device_p;
    struct rsbac_acl_device_list_item_t * new_device_p;
    u_long flags;

    if (!rsbac_is_initialized())
      {
        printk(KERN_WARNING "rsbac_mount_acl(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
      }
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_ds_acl)
      printk(KERN_DEBUG "rsbac_mount_acl(): mounting device %02u:%02u\n",
             MAJOR(kdev),MINOR(kdev));
#endif
    /* wait for read access to device_list_head */
    rsbac_read_lock(&device_list_head.lock, &flags);
    device_p = acl_lookup_device(kdev);
    /* repeated mount? */
    if(device_p)
      {
        #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
        printk(KERN_WARNING "rsbac_mount_acl: repeated mount of device %02u:%02u\n",
               MAJOR(kdev), MINOR(kdev));
	#else
        printk(KERN_INFO "rsbac_mount_acl: repeated mount %u of device %02u:%02u\n",
               device_p->mount_count, MAJOR(kdev), MINOR(kdev));
	device_p->mount_count++;
	#endif
        rsbac_read_unlock(&device_list_head.lock, &flags);
        return 0;
      }
    rsbac_read_unlock(&device_list_head.lock, &flags);
    /* OK, go on */
    new_device_p = create_device_item(kdev); 
    if(!new_device_p)
      return -RSBAC_ECOULDNOTADDDEVICE;

    if((err = acl_register_fd_lists(new_device_p, kdev)))
      {
        char * tmp;

        tmp = rsbac_kmalloc(RSBAC_MAXNAMELEN);
        if(tmp)
          {
            printk(KERN_WARNING
                   "rsbac_mount_acl(): File/Dir ACL registration failed for dev %02u:%02u, err %s!\n",
                   MAJOR(kdev), MINOR(kdev), get_error_name(tmp,err));
            rsbac_kfree(tmp);
          }
      }

    /* wait for read access to device_list_head */
    rsbac_read_lock(&device_list_head.lock, &flags);
    /* make sure to only add, if this device item has not been added in the meantime */
    device_p = acl_lookup_device(kdev);
    if(device_p)
      {
        printk(KERN_WARNING
               "rsbac_mount_acl(): mount race for device %02u:%02u detected!\n",
               MAJOR(kdev), MINOR(kdev));
        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
	device_p->mount_count++;
	#endif
        /* also detaches lists */
	clear_device_item(new_device_p);
        rsbac_read_unlock(&device_list_head.lock, &flags);
      }
    else
      {
        rsbac_read_unlock(&device_list_head.lock, &flags);
        rsbac_write_lock(&device_list_head.lock, &flags);
        device_p = add_device_item(new_device_p);
        rsbac_write_unlock(&device_list_head.lock, &flags);
        if(!device_p)
          {
            printk(KERN_WARNING "rsbac_mount_acl: adding device %02u:%02u failed!\n",
                   MAJOR(kdev), MINOR(kdev));
            /* also detaches lists */
            clear_device_item(new_device_p);
            err = -RSBAC_ECOULDNOTADDDEVICE;
          }
      }

    return(err);
  };
  
/* When umounting a device, its file/dir ACLs must be removed. */

int rsbac_umount_acl(kdev_t kdev)
  {
    u_long flags;
    struct rsbac_acl_device_list_item_t * device_p;

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

#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_ds)
      printk(KERN_DEBUG "rsbac_umount_acl(): umounting device %02u:%02u\n",
             MAJOR(kdev), MINOR(kdev));
#endif
    /* sync of attribute lists was done in rsbac_umount */
    /* wait for write access to device_list_head */
    rsbac_write_lock(&device_list_head.lock, &flags);
    /* OK, nobody else is working on it... */
    device_p = acl_lookup_device(kdev);
    if(device_p)
      {
        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        if(device_p->mount_count == 1)
        #endif
          remove_device_item(kdev);
        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        else
          {
            if(device_p->mount_count > 1)
              {
                device_p->mount_count--;
              }
            else
              {
                printk(KERN_WARNING "rsbac_umount_acl: device %02u:%02u has mount_count < 1!\n",
                       MAJOR(kdev), MINOR(kdev));
              }
          }
        #endif
      }
    /* allow access */
    rsbac_write_unlock(&device_list_head.lock, &flags);
    return(0);
  };

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

int rsbac_stats_acl(void)
  {
    u_int                                     item_count = 0;
    u_int                                     member_count = 0;
    int    tmp_count;
    u_int  i;
    u_long dflags;
    struct rsbac_acl_device_list_item_t     * device_p;

    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if (!rsbac_is_initialized)
      {
        printk(KERN_WARNING "rsbac_stats_acl(): RSBAC not initialized\n");
        return(-RSBAC_ENOTINITIALIZED);
      }
#ifdef CONFIG_RSBAC_DEBUG
    if (rsbac_debug_aef_acl)
      printk(KERN_DEBUG "rsbac_stats_acl(): 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;
      }

    printk(KERN_INFO "ACL Status\n-----------\n");

    /* protect device list */
    rsbac_read_lock(&device_list_head.lock, &dflags);
    device_p = device_list_head.head;
    while(device_p)
      {
        /* reset counters */
        item_count = 0;
        member_count = 0;
        for(i=0; i<RSBAC_ACL_NR_FD_LISTS; i++)
          {
            tmp_count = rsbac_list_lol_count(device_p->handles[i]);
            if(tmp_count > 0)
              item_count+=tmp_count;
            tmp_count = rsbac_list_lol_all_subcount(device_p->handles[i]);
            if(tmp_count > 0)
              member_count += tmp_count;
          }
        printk(KERN_INFO
               "device %02u:%02u has %u file ACLs, sum of %u members\n",
               MAJOR(device_p->id),
               MINOR(device_p->id),
               item_count,
               member_count);
        device_p = device_p->next;
      }
    /* unprotect device list */
    rsbac_read_unlock(&device_list_head.lock, &dflags);

    /* dev list */
    printk(KERN_INFO
           "%li device ACL items, sum of %li members\n",
           rsbac_list_lol_count(dev_handle),
           rsbac_list_lol_all_subcount(dev_handle));

    /* SCD list */
    printk(KERN_INFO
           "%li scd ACL items, sum of %li members\n",
           rsbac_list_lol_count(scd_handle),
           rsbac_list_lol_all_subcount(scd_handle));

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    /* netdev list */
    printk(KERN_INFO
           "%li network device ACL items, sum of %li members\n",
           rsbac_list_lol_count(netdev_handle),
           rsbac_list_lol_all_subcount(netdev_handle));
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    /* nettemp_nt list */
    printk(KERN_INFO
           "%li network template NT ACL items, sum of %li members\n",
           rsbac_list_lol_count(nettemp_nt_handle),
           rsbac_list_lol_all_subcount(nettemp_nt_handle));
    /* nettemp list */
    printk(KERN_INFO
           "%li network template ACL items, sum of %li members\n",
           rsbac_list_lol_count(nettemp_handle),
           rsbac_list_lol_all_subcount(nettemp_handle));
    /* netobj list */
    printk(KERN_INFO
           "%li network object ACL items, sum of %li members\n",
           rsbac_list_lol_count(netobj_handle),
           rsbac_list_lol_all_subcount(netobj_handle));
#endif

    printk(KERN_INFO
           "%li groups, last new is %u\n",
           rsbac_list_count(group_handle),
           group_last_new);

    /* protect gm list */
    printk(KERN_INFO
           "%li group member items, sum of %li group memberships\n",
           rsbac_list_lol_count(gm_handle),
           rsbac_list_lol_all_subcount(gm_handle));

    return(0);
  };

/***************************************************/
/* consistency checking (as far as possible)       */

int rsbac_check_acl(int correct, int check_inode)
  {
    struct rsbac_acl_device_list_item_t * device_p;
    u_long                              f_count = 0, f_sum = 0, tmp_count,
                                        r_count, u_count, b_count, no_member_count;
    int                                 list_no;
    u_long                              dflags;
    long                                desc_count;
    long                                sub_desc_count;
    rsbac_inode_nr_t                  * fd_desc_p;
    struct rsbac_dev_t                * dev_desc_p;
    __u8                              * scd_desc_p;
#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    rsbac_netdev_id_t                 * netdev_desc_p;
#endif
#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    rsbac_net_temp_id_t               * nettemp_desc_p;
    rsbac_net_obj_id_t                * netobj_desc_p;
#endif
    struct rsbac_acl_entry_desc_t     * sub_desc_p;
    struct super_block                * sb_p;
    struct inode                      * inode_p;
    rsbac_uid_t                       * user_p;
    rsbac_acl_group_id_t              * group_p;
    u_int  i,j;

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

    /* group membership list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(gm_handle, (void **) &user_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            sub_desc_count = rsbac_list_lol_get_all_subdesc(gm_handle, &user_p[i], (void **) &group_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(!rsbac_list_exist(group_handle, &group_p[j]))
                      {
                        printk(KERN_WARNING
                               "rsbac_check_acl(): removing user %u membership in non-existent group %u!\n",
                               user_p[i], group_p[j]);
                        rsbac_list_lol_subremove(gm_handle, &user_p[i], &group_p[j]);
                      }
                  }
                vfree(group_p);
              }
            else
              {
                /* remove empty membership list */
                if(!sub_desc_count)
                  rsbac_list_lol_remove(gm_handle, &user_p[i]);
              }
          }
        vfree(user_p);
      }
    /* recalculated values! */
    printk(KERN_INFO "rsbac_check_acl(): %li group membership items\n",
           rsbac_list_lol_count(gm_handle));

    /* group list */
    printk(KERN_INFO "rsbac_check_acl(): %li group items\n",
                 rsbac_list_count(group_handle));


    /* wait for read access to device_list_head */
    rsbac_read_lock(&device_list_head.lock, &dflags);
    /* OK, go on */
/*    printk(KERN_INFO "rsbac_check_acl(): currently %u processes working on file/dir aci\n",
                     device_list_head.lock.lock); */
    device_p = device_list_head.head;
    while (device_p)
      { /* for all sublists */
        f_count = 0;
        r_count = 0;
        u_count = 0;
        b_count = 0;
        no_member_count = 0;
        if(check_inode)
          {
            sb_p = rsbac_get_super_block(device_p->id);
            if(!sb_p)
              {
                printk(KERN_WARNING "rsbac_check_acl(): no super block for device %02u:%02u!\n",
                       MAJOR(device_p->id), MINOR(device_p->id));
              }
            else
              {
                /* is last write finished? (only, if writable) */
                if(writable(sb_p))
                  {
                    /* sync to be sure */
                    printk(KERN_INFO "rsbac_check_acl(): syncing device %02u:%02u\n",
                           MAJOR(device_p->id), MINOR(device_p->id));
                    fsync_dev(device_p->id);
                  }
              }
          }
        else
          sb_p = NULL;

        /* OK, go ahead */
        for(list_no = 0; list_no < RSBAC_ACL_NR_FD_LISTS; list_no++)
          {
/*            printk(KERN_INFO "rsbac_check_acl(): list %u\n",
                   list_no); */
            tmp_count = 0;
            desc_count = rsbac_list_lol_get_all_desc(device_p->handles[list_no], (void **) &fd_desc_p);
            if(desc_count > 0)
              {
                for(i=0; i<desc_count; i++)
                  {
                    /* check for inode on disk (but not for reiserfs, because of 64bit inode numbers) */
                    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                    if(sb_p)
                    #else
                    if(sb_p && !sb_p->s_op->read_inode2)
                    #endif
                      {
                        inode_p = iget(sb_p, fd_desc_p[i]);
                        if(is_bad_inode(inode_p))
                          { /* inode is bad -> remove */
                            b_count++;
                            if(correct)
                              {
                                printk(KERN_INFO
                                       "rsbac_check_acl(): fd_item for bad inode %u on device %02u:%02u, list %u, removing!\n",
                                        fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no);
                                rsbac_list_lol_remove(device_p->handles[list_no], &fd_desc_p[i]);
                                continue;
                              }
                            else
                              {
                                printk(KERN_INFO
                                       "rsbac_check_acl(): fd_item for bad inode %u on device %02u:%02u, list %u!\n",
                                       fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no);
                              }
                          } /* end of bad_inode */
                        else
                          { /* good inode */
                            /* currently only deletion checking of ext2 inodes is possible */
                            if(sb_p->s_magic == EXT2_SUPER_MAGIC)
                              {
                                if(inode_p->u.ext2_i.i_dtime)
                                  { /* inode has been deleted -> remove */
                                    r_count++;
                                    if(correct)
                                      {
                                        printk(KERN_INFO
                                               "rsbac_check_acl(): fd_item for deleted inode %u on device %02u:%02u, list %u, removing!\n",
                                               fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no);
                                        rsbac_list_lol_remove(device_p->handles[list_no], &fd_desc_p[i]);
                                        continue;
                                      }
                                    else
                                      {
                                        printk(KERN_INFO
                                               "rsbac_check_acl(): fd_item for deleted inode %u on device %02u:%02u, list %u!\n",
                                               fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no);
                                      }
                                  }
                                else
                                  {
                                    if(inode_p->i_nlink <= 0)
                                      { /* inode has been unlinked, but no dtime is set -> warn */
                                        u_count++;
                                        if(correct >= 2)
                                          {
                                            printk(KERN_INFO
                                                   "rsbac_check_acl(): fd_item for inode %u with nlink <= 0 on device %02u:%02u, list %u, removing!\n",
                                                   fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no);
                                            rsbac_list_lol_remove(device_p->handles[list_no], &fd_desc_p[i]);
                                            continue;
                                          }
                                        else
                                          {
                                            printk(KERN_INFO
                                                   "rsbac_check_acl(): deleted inode %u on device %02u:%02u, list %u, has no dtime!\n",
                                                   fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no);
                                          }
                                      }
                                  }
                              }
                          } /* end of is_good_inode */
                        iput(inode_p);
                      } /* end of sb_p */

                    /* check for group existence of all ACL entries for groups */
                    sub_desc_count = rsbac_list_lol_get_all_subdesc(device_p->handles[list_no],
                                                                    &fd_desc_p[i],
                                                                    (void **) &sub_desc_p);
                    if(sub_desc_count > 0)
                      {
                        for(j=0; j<sub_desc_count; j++)
                          {
                            if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                               && sub_desc_p[j].subj_id
                               && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                              {
                                if(correct)
                                  {
                                    /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                                    if(rsbac_debug_ds)
                                      printk(KERN_DEBUG
                                             "rsbac_check_acl(): fd_item for inode %u on device %02u:%02u, list %u, has invalid group %u in ACL -> removing entry!\n",
                                             fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no, sub_desc_p[j].subj_id);
#endif
                                    rsbac_list_lol_subremove(device_p->handles[list_no],
                                                             &fd_desc_p[i], &sub_desc_p[j]);
                                  }
                                else
                                  {
                                    /* complain */
#ifdef CONFIG_RSBAC_DEBUG
                                    if(rsbac_debug_ds)
                                      printk(KERN_DEBUG
                                             "rsbac_check_acl(): fd_item for inode %u on device %02u:%02u, list %u, has invalid group %u in ACL!\n",
                                             fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no, sub_desc_p[j].subj_id);
#endif
                                  }
                              }
                            #if defined(CONFIG_RSBAC_RC)
                            else
                            if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                               && (sub_desc_p[j].subj_id > RC_role_max_value)
                              )
                              {
                                if(correct)
                                  {
                                    /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                                    if(rsbac_debug_ds)
                                      printk(KERN_DEBUG
                                             "rsbac_check_acl(): fd_item for inode %u on device %02u:%02u, list %u, has invalid RC role %u in ACL -> removing entry!\n",
                                             fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no, sub_desc_p[j].subj_id);
#endif
                                    rsbac_list_lol_subremove(device_p->handles[list_no],
                                                             &fd_desc_p[i], &sub_desc_p[j]);
                                  }
                                else
                                  {
                                    /* complain */
#ifdef CONFIG_RSBAC_DEBUG
                                    if(rsbac_debug_ds)
                                      printk(KERN_DEBUG
                                             "rsbac_check_acl(): fd_item for inode %u on device %02u:%02u, list %u, has invalid role %u in ACL!\n",
                                             fd_desc_p[i], MAJOR(device_p->id), MINOR(device_p->id), list_no, sub_desc_p[j].subj_id);
#endif
                                  }
                              }
                            #endif
                          }
                        vfree(sub_desc_p);
                      }
                  }
                tmp_count++;
                vfree(fd_desc_p);
                f_count += desc_count;
              }
          } /* end of for-fd-list-array */

        switch(correct)
          {
            case 2:  printk(KERN_INFO
                            "rsbac_check_acl(): Device %02u:%02u has %lu file/dir ACLs (%lu removed (%lu bad inodes, %lu dtimed inodes, %lu unlinked inodes, %lu had no members and default mask))\n",
                            MAJOR(device_p->id), MINOR(device_p->id), f_count, b_count + r_count + u_count + no_member_count,
                            b_count, r_count, u_count, no_member_count);
                            break;
            case 1:  printk(KERN_INFO
                            "rsbac_check_acl(): Device %02u:%02u has %lu file/dir ACLs (%lu removed (%lu bad inodes, %lu dtimed inodes, %lu had no members and default mask), %lu unlinked inodes)\n",
                            MAJOR(device_p->id), MINOR(device_p->id), f_count, b_count + r_count + no_member_count,
                            b_count, r_count, no_member_count, u_count);
                            break;
            default: printk(KERN_INFO
                            "rsbac_check_acl(): Device %02u:%02u has %lu file/dir ACLs (%lu with bad inodes, %lu with dtimed inodes, %lu unlinked inodes, %lu without members and with default mask)\n",
                            MAJOR(device_p->id), MINOR(device_p->id), f_count,
                            b_count, r_count, u_count, no_member_count);
          }
        f_sum += f_count;
        /* go on */
        device_p = device_p->next;
      };
    printk(KERN_INFO "rsbac_check_acl(): Sum of %u Devices with %lu file/dir ACLs\n",
                 device_list_head.count, f_sum);
    /* free access to device_list_head */
    rsbac_read_unlock(&device_list_head.lock, &dflags);

    /* dev list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(dev_handle, (void **) &dev_desc_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            /* check for group existence of all ACL entries for groups */
            sub_desc_count = rsbac_list_lol_get_all_subdesc(dev_handle,
                                                            &dev_desc_p[i],
                                                            (void **) &sub_desc_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                       && sub_desc_p[j].subj_id
                       && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): dev_item %c%02u:%02u, has invalid group %u in ACL -> removing entry!\n",
                                     'B'+dev_desc_p[i].type, MAJOR(dev_desc_p[i].id), MINOR(dev_desc_p[i].id), sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(dev_handle, &dev_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): dev_item %c%02u:%02u, has invalid group %u in ACL!\n",
                                     'B'+dev_desc_p[i].type, MAJOR(dev_desc_p[i].id), MINOR(dev_desc_p[i].id), sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #if defined(CONFIG_RSBAC_RC)
                    else
                    if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                       && (sub_desc_p[j].subj_id > RC_role_max_value)
                      )
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): dev_item %c%02u:%02u, has invalid role %u in ACL -> removing entry!\n",
                                     'B'+dev_desc_p[i].type, MAJOR(dev_desc_p[i].id), MINOR(dev_desc_p[i].id), sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(dev_handle, &dev_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): dev_item %c%02u:%02u, has invalid role %u in ACL!\n",
                                     'B'+dev_desc_p[i].type, MAJOR(dev_desc_p[i].id), MINOR(dev_desc_p[i].id), sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #endif
                  }
                vfree(sub_desc_p);
              }
          }
        vfree(dev_desc_p);
        f_sum += desc_count;
      }
    printk(KERN_INFO "rsbac_check_acl(): %li device items\n",
           desc_count);

    /* SCD list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(scd_handle, (void **) &scd_desc_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            /* check for group existence of all ACL entries for groups */
            sub_desc_count = rsbac_list_lol_get_all_subdesc(scd_handle,
                                                            &scd_desc_p[i],
                                                            (void **) &sub_desc_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                       && sub_desc_p[j].subj_id
                       && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): scd_item %u has invalid group %u in ACL -> removing entry!\n",
                                     scd_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(scd_handle, &scd_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): scd_item %u has invalid group %u in ACL!\n",
                                     scd_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #if defined(CONFIG_RSBAC_RC)
                    else
                    if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                       && (sub_desc_p[j].subj_id > RC_role_max_value)
                      )
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): scd_item %u has invalid role %u in ACL -> removing entry!\n",
                                     scd_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(scd_handle, &scd_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): scd_item %u has invalid role %u in ACL!\n",
                                     scd_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #endif
                  }
                vfree(sub_desc_p);
              }
          }
        vfree(scd_desc_p);
        f_sum += desc_count;
      }
    printk(KERN_INFO "rsbac_check_acl(): %li SCD items\n",
           desc_count);

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    /* netdev list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(netdev_handle, (void **) &netdev_desc_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            /* check for group existence of all ACL entries for groups */
            sub_desc_count = rsbac_list_lol_get_all_subdesc(netdev_handle,
                                                            &netdev_desc_p[i],
                                                            (void **) &sub_desc_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                       && sub_desc_p[j].subj_id
                       && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netdev_item %s has invalid group %u in ACL -> removing entry!\n",
                                     netdev_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(netdev_handle, &netdev_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netdev_item %s has invalid group %u in ACL!\n",
                                     netdev_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #if defined(CONFIG_RSBAC_RC)
                    else
                    if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                       && (sub_desc_p[j].subj_id > RC_role_max_value)
                      )
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netdev_item %s has invalid role %u in ACL -> removing entry!\n",
                                     netdev_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(netdev_handle, &netdev_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netdev_item %s has invalid role %u in ACL!\n",
                                     netdev_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #endif
                  }
                vfree(sub_desc_p);
              }
          }
        vfree(netdev_desc_p);
        f_sum += desc_count;
      }
    printk(KERN_INFO "rsbac_check_acl(): %li network device items\n",
           desc_count);
#endif /* NET_DEV_PROT */

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    /* nettemp_nt list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(nettemp_nt_handle, (void **) &nettemp_desc_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            /* check for group existence of all ACL entries for groups */
            sub_desc_count = rsbac_list_lol_get_all_subdesc(nettemp_nt_handle,
                                                            &nettemp_desc_p[i],
                                                            (void **) &sub_desc_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                       && sub_desc_p[j].subj_id
                       && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_nt_item %u has invalid group %u in ACL -> removing entry!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(nettemp_nt_handle, &nettemp_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_nt_item %u has invalid group %u in ACL!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #if defined(CONFIG_RSBAC_RC)
                    else
                    if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                       && (sub_desc_p[j].subj_id > RC_role_max_value)
                      )
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_nt_item %u has invalid role %u in ACL -> removing entry!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(nettemp_nt_handle, &nettemp_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_nt_item %u has invalid role %u in ACL!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #endif
                  }
                vfree(sub_desc_p);
              }
          }
        vfree(nettemp_desc_p);
        f_sum += desc_count;
      }
    printk(KERN_INFO "rsbac_check_acl(): %li network template NT items\n",
           desc_count);

    /* nettemp list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(nettemp_handle, (void **) &nettemp_desc_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            /* check for group existence of all ACL entries for groups */
            sub_desc_count = rsbac_list_lol_get_all_subdesc(nettemp_handle,
                                                            &nettemp_desc_p[i],
                                                            (void **) &sub_desc_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                       && sub_desc_p[j].subj_id
                       && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_item %u has invalid group %u in ACL -> removing entry!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(nettemp_handle, &nettemp_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_item %u has invalid group %u in ACL!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #if defined(CONFIG_RSBAC_RC)
                    else
                    if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                       && (sub_desc_p[j].subj_id > RC_role_max_value)
                      )
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_item %u has invalid role %u in ACL -> removing entry!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(nettemp_handle, &nettemp_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): nettemp_item %u has invalid role %u in ACL!\n",
                                     nettemp_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #endif
                  }
                vfree(sub_desc_p);
              }
          }
        vfree(nettemp_desc_p);
        f_sum += desc_count;
      }
    printk(KERN_INFO "rsbac_check_acl(): %li network template items\n",
           desc_count);

    /* netobj list */
    tmp_count = 0;
    desc_count = rsbac_list_lol_get_all_desc(netobj_handle, (void **) &netobj_desc_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            /* check for group existence of all ACL entries for groups */
            sub_desc_count = rsbac_list_lol_get_all_subdesc(netobj_handle,
                                                            &netobj_desc_p[i],
                                                            (void **) &sub_desc_p);
            if(sub_desc_count > 0)
              {
                for(j=0; j<sub_desc_count; j++)
                  {
                    if(   (sub_desc_p[j].subj_type == ACLS_GROUP)
                       && sub_desc_p[j].subj_id
                       && !rsbac_list_exist(group_handle, &sub_desc_p[j].subj_id))
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netobj_item %p has invalid group %u in ACL -> removing entry!\n",
                                     netobj_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(netobj_handle, &netobj_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netobj_item %p has invalid group %u in ACL!\n",
                                     netobj_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #if defined(CONFIG_RSBAC_RC)
                    else
                    if(   (sub_desc_p[j].subj_type == ACLS_ROLE)
                       && (sub_desc_p[j].subj_id > RC_role_max_value)
                      )
                      {
                        if(correct)
                          {
                            /* remove sub item and complain */
#ifdef CONFIG_RSBAC_DEBUG
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netobj_item %p has invalid role %u in ACL -> removing entry!\n",
                                     netobj_desc_p[i], sub_desc_p[j].subj_id);
#endif
                            rsbac_list_lol_subremove(netobj_handle, &netobj_desc_p[i], &sub_desc_p[j]);
                          }
                        else
                          {
#ifdef CONFIG_RSBAC_DEBUG
                            /* complain */
                            if(rsbac_debug_ds)
                              printk(KERN_DEBUG
                                     "rsbac_check_acl(): netobj_item %p has invalid role %u in ACL!\n",
                                     netobj_desc_p[i], sub_desc_p[j].subj_id);
#endif
                          }
                      }
                    #endif
                  }
                vfree(sub_desc_p);
              }
          }
        vfree(netobj_desc_p);
        f_sum += desc_count;
      }
    printk(KERN_INFO "rsbac_check_acl(): %li network object items\n",
           desc_count);
#endif /* NET_OBJ_PROT */

    printk(KERN_INFO
           "rsbac_check_acl(): Total of %lu registered ACLs\n",
           f_sum);
    return(0);
  };

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

/* All these procedures handle the spinlocks to protect the targets during */
/* access.                                                                 */

/* rsbac_acl_set_acl_entry
 * Set ACL entry for given target and subject to given rights. If entry does
 * not exist, it is created, thus cutting the inheritance from default/parent.
 */

int rsbac_acl_set_acl_entry        (enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id,
                                           rsbac_acl_rights_vector_t   rights,
                                           rsbac_time_t                ttl)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      struct rsbac_acl_entry_desc_t           desc;
      u_long                                  dflags;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_set_acl_entry(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (subj_type >= ACLS_NONE)
        return(-RSBAC_EINVALIDVALUE);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_set_acl_entry(): called from interrupt!\n");
        }
#endif
      desc.subj_type = subj_type;
      desc.subj_id = subj_id;

      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting file/dir/fifo/symlink ACL for device %02u:%02u, inode %u\n",
                         MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
                return rsbac_list_add_ttl(default_fd_handle, ttl, &desc, &rights);
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_set_acl_entry(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            list_no = fd_hash(tid.file.inode);
            if(!rsbac_list_lol_exist(device_p->handles[list_no], &tid.file.inode))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_FD_MASK;

                err = rsbac_list_lol_add(device_p->handles[list_no], &tid.file.inode, &mask);
                if(err)
                  {
                    rsbac_read_unlock(&device_list_head.lock, &dflags);
                    return err;
                  }
              }
            err = rsbac_list_lol_subadd_ttl(device_p->handles[list_no], ttl, &tid.file.inode, &desc, &rights);
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            /* ready. */
            return err;

          case T_DEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting device ACL for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            /* default entry? */
            if((tid.dev.type == D_none) && !tid.dev.id)
                return rsbac_list_add_ttl(default_dev_handle, ttl, &desc, &rights);

            if(!rsbac_list_lol_exist(dev_handle, &tid.dev))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_DEV_MASK;

                err = rsbac_list_lol_add(dev_handle, &tid.dev, &mask);
                if(err)
                  return err;
              }
            return rsbac_list_lol_subadd_ttl(dev_handle, ttl, &tid.dev, &desc, &rights);

          case T_IPC:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting IPC ACL for type %u\n",
                       tid.ipc.type);
#endif
*/
            /* default entry? */
            if(tid.ipc.type == I_none)
              return rsbac_list_add_ttl(default_ipc_handle, ttl, &desc, &rights);
            else
              return -RSBAC_EINVALIDTARGET;

          case T_SCD:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
              {
                char tmp[80];
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting SCD ACL for %s\n",
                       get_acl_scd_type_name(tmp, tid.scd));
              }
#endif
*/
            /* default entry? */
            if(tid.scd == AST_none)
                return rsbac_list_add_ttl(default_scd_handle, ttl, &desc, &rights);

            if(!rsbac_list_lol_exist(scd_handle, &tid.scd))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_SCD_MASK;

                err = rsbac_list_lol_add(scd_handle, &tid.scd, &mask);
                if(err)
                  return err;
              }
            return rsbac_list_lol_subadd_ttl(scd_handle, ttl, &tid.scd, &desc, &rights);

          case T_USER:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting user ACL for user %u\n",
                       tid.user);
#endif
*/
            /* default entry? */
            if(tid.user == RSBAC_NO_USER)
              return rsbac_list_add_ttl(default_u_handle, ttl, &desc, &rights);
            else
              return -RSBAC_EINVALIDTARGET;

          case T_PROCESS:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting process ACL for pid %u\n",
                       tid.process);
#endif
*/
            /* default entry? */
            if(!tid.process)
              return rsbac_list_add_ttl(default_p_handle, ttl, &desc, &rights);
            else
              return -RSBAC_EINVALIDTARGET;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting network device ACL for netdev %s\n",
                       tid.netdev);
#endif
            /* default entry? */
            if(!tid.netdev[0])
                return rsbac_list_add_ttl(default_netdev_handle, ttl, &desc, &rights);

            if(!rsbac_list_lol_exist(netdev_handle, &tid.netdev))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETDEV_MASK;

                err = rsbac_list_lol_add(netdev_handle, &tid.netdev, &mask);
                if(err)
                  return err;
              }
            return rsbac_list_lol_subadd_ttl(netdev_handle, ttl, &tid.netdev, &desc, &rights);
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting network template NT ACL for nettemp_nt %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
                return rsbac_list_add_ttl(default_nettemp_nt_handle, ttl, &desc, &rights);

            if(!rsbac_list_lol_exist(nettemp_nt_handle, &tid.nettemp))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETTEMP_MASK;

                err = rsbac_list_lol_add(nettemp_nt_handle, &tid.nettemp, &mask);
                if(err)
                  return err;
              }
            return rsbac_list_lol_subadd_ttl(nettemp_nt_handle, ttl, &tid.nettemp, &desc, &rights);

          case T_NETTEMP:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting network template ACL for nettemp %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;

            if(!rsbac_list_lol_exist(nettemp_handle, &tid.nettemp))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;

                err = rsbac_list_lol_add(nettemp_handle, &tid.nettemp, &mask);
                if(err)
                  return err;
              }
            return rsbac_list_lol_subadd_ttl(nettemp_handle, ttl, &tid.nettemp, &desc, &rights);

          case T_NETOBJ:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_acl_entry(): Setting network object ACL for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            /* default entry? */
            if(!tid.netobj.sock_p)
                return rsbac_list_add_ttl(default_netobj_handle, ttl, &desc, &rights);

            if(!rsbac_list_lol_exist(netobj_handle, &tid.netobj.sock_p))
              {
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;

                err = rsbac_list_lol_add(netobj_handle, &tid.netobj.sock_p, &mask);
                if(err)
                  return err;
              }
            return rsbac_list_lol_subadd_ttl(netobj_handle, ttl, &tid.netobj.sock_p, &desc, &rights);
#endif /* NET_OBJ_PROT */


          default:
            err = -RSBAC_EINVALIDTARGET;
        }
      return(err);
  }

/* rsbac_acl_remove_acl_entry
 * Remove ACL entry for given target and subject. This reactivates the
 * inheritance from default/parent.
 */

int rsbac_acl_remove_acl_entry     (enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      struct rsbac_acl_entry_desc_t           desc;
      u_long                                  dflags;
      rsbac_acl_rights_vector_t               mask;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_remove_acl_entry(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (subj_type >= ACLS_NONE)
        return(-RSBAC_EINVALIDVALUE);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_remove_acl_entry(): called from interrupt!\n");
        }
#endif
      desc.subj_type = subj_type;
      desc.subj_id = subj_id;

      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
              {
                char tmp[RSBAC_MAXNAMELEN];

                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing file/dir/fifo/symlink ACL entry %s %u for device %02u:%02u, inode %u\n",
                       get_acl_subject_type_name(tmp,desc.subj_type), desc.subj_id,
                       MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
              }
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
                return rsbac_list_remove(default_fd_handle, &desc);

            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_remove_acl_entry(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            list_no = fd_hash(tid.file.inode);
            err = rsbac_list_lol_subremove(device_p->handles[list_no], &tid.file.inode, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(device_p->handles[list_no], &tid.file.inode)
               && !rsbac_list_lol_get_data(device_p->handles[list_no],
                                           &tid.file.inode,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_FD_MASK)
              )
              {
                err = rsbac_list_lol_remove(device_p->handles[list_no], &tid.file.inode);
              }
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            /* ready. */
            return err;

          case T_DEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing device ACL entry for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            /* default entry? */
            if((tid.dev.type == D_none) && !tid.dev.id)
                return rsbac_list_remove(default_dev_handle, &desc);

            err = rsbac_list_lol_subremove(dev_handle, &tid.dev, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(dev_handle, &tid.dev)
               && !rsbac_list_lol_get_data(dev_handle,
                                           &tid.dev,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_DEV_MASK)
              )
              {
                err = rsbac_list_lol_remove(dev_handle, &tid.dev);
              }
            return err;

          case T_IPC:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing IPC ACL for type %u\n",
                       tid.ipc.type);
#endif
            /* default entry? */
            if(tid.ipc.type == I_none)
              return rsbac_list_remove(default_ipc_handle, &desc);
            else
              return -RSBAC_EINVALIDTARGET;

          case T_SCD:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                {
                  char tmp[80];

                  printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing SCD ACL entry for %s\n",
                         get_acl_scd_type_name(tmp, tid.scd));
                }
#endif
            /* default entry? */
            if(tid.scd == AST_none)
              return rsbac_list_remove(default_scd_handle, &desc);
            err = rsbac_list_lol_subremove(scd_handle, &tid.scd, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(scd_handle, &tid.scd)
               && !rsbac_list_lol_get_data(scd_handle,
                                           &tid.scd,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_SCD_MASK)
              )
              {
                err = rsbac_list_lol_remove(scd_handle, &tid.scd);
              }
            return err;

          case T_USER:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing user ACL for user %u\n",
                       tid.user);
#endif
            /* default entry? */
            if(tid.user == RSBAC_NO_USER)
              return rsbac_list_remove(default_u_handle, &desc);
            else
              return -RSBAC_EINVALIDTARGET;

          case T_PROCESS:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing process ACL for pid %u\n",
                       tid.process);
#endif
            /* default entry? */
            if(!tid.process)
              return rsbac_list_remove(default_p_handle, &desc);
            else
              return -RSBAC_EINVALIDTARGET;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing network device ACL entry for netdev %s\n",
                       tid.netdev);
#endif
            /* default entry? */
            if(!tid.netdev[0])
                return rsbac_list_remove(default_netdev_handle, &desc);

            err = rsbac_list_lol_subremove(netdev_handle, &tid.netdev, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(netdev_handle, &tid.netdev)
               && !rsbac_list_lol_get_data(netdev_handle,
                                           &tid.netdev,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_NETDEV_MASK)
              )
              {
                err = rsbac_list_lol_remove(netdev_handle, &tid.netdev);
              }
            return err;
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing network template NT ACL entry for nettemp_nt %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
                return rsbac_list_remove(default_nettemp_nt_handle, &desc);
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;

            err = rsbac_list_lol_subremove(nettemp_nt_handle, &tid.nettemp, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(nettemp_nt_handle, &tid.nettemp)
               && !rsbac_list_lol_get_data(nettemp_nt_handle,
                                           &tid.nettemp,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_NETTEMP_MASK)
              )
              {
                err = rsbac_list_lol_remove(nettemp_nt_handle, &tid.nettemp);
              }
            return err;

          case T_NETTEMP:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing network template ACL entry for nettemp_nt %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;

            err = rsbac_list_lol_subremove(nettemp_handle, &tid.nettemp, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(nettemp_handle, &tid.nettemp)
               && !rsbac_list_lol_get_data(nettemp_handle,
                                           &tid.nettemp,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_NETOBJ_MASK)
              )
              {
                err = rsbac_list_lol_remove(nettemp_handle, &tid.nettemp);
              }
            return err;

          case T_NETOBJ:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl_entry(): Removing network object ACL entry for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            /* default entry? */
            if(!tid.netobj.sock_p)
                return rsbac_list_remove(default_netobj_handle, &desc);

            err = rsbac_list_lol_subremove(netobj_handle, &tid.netobj.sock_p, &desc);
            /* if ACL is empty, remove it */
            if(   !err
               && !rsbac_list_lol_subcount(netobj_handle, &tid.netobj.sock_p)
               && !rsbac_list_lol_get_data(netobj_handle,
                                           &tid.netobj,
                                           &mask)
               && (mask == RSBAC_ACL_DEFAULT_NETOBJ_MASK)
              )
              {
                err = rsbac_list_lol_remove(netobj_handle, &tid.netobj.sock_p);
              }
            return err;
#endif /* NET_OBJ_PROT */

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  }

/* rsbac_acl_remove_acl
 * Remove ACL for given target. For cleanup on delete.
 */

int rsbac_acl_remove_acl     (enum   rsbac_target_t              target,
                              union  rsbac_target_id_t           tid)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      u_long                                  dflags;
    
      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_remove_acl(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_remove_acl(): called from interrupt!\n");
        }
#endif
      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing file/dir/fifo/symlink ACL for device %02u:%02u, inode %u\n",
                       MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              return -RSBAC_EINVALIDTARGET;

            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_remove_acl(): Could not lookup device!\n");
                err = -RSBAC_EINVALIDDEV;
              }
            else
              {
                list_no = fd_hash(tid.file.inode);
                err = rsbac_list_lol_remove(device_p->handles[list_no], &tid.file.inode);
              }
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            /* ready. */
            return err;

          case T_DEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing device ACL for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            /* default entry? */
            if((tid.dev.type == D_none) && !tid.dev.id)
              return -RSBAC_EINVALIDTARGET;
            else
              return rsbac_list_lol_remove(dev_handle, &tid.dev);

          case T_SCD:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                {
                  char tmp[80];

                  printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing SCD ACL for %s\n",
                         get_acl_scd_type_name(tmp, tid.scd));
                }
#endif
            /* default entry? */
            if(tid.scd == AST_none)
              return -RSBAC_EINVALIDTARGET;
            else
              return rsbac_list_lol_remove(scd_handle, &tid.scd);

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing network device ACL for netdev %s\n",
                       tid.netdev);
#endif
            /* default entry? */
            if(!tid.netdev[0])
              return -RSBAC_EINVALIDTARGET;
            else
              return rsbac_list_lol_remove(netdev_handle, &tid.netdev);
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing network template NT ACL for nettemp_nt %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
              return -RSBAC_EINVALIDTARGET;
            else
              return rsbac_list_lol_remove(nettemp_nt_handle, &tid.nettemp);
          case T_NETTEMP:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing network template ACL for nettemp %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
              return -RSBAC_EINVALIDTARGET;
            else
              return rsbac_list_lol_remove(nettemp_handle, &tid.nettemp);
          case T_NETOBJ:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_acl(): Removing network object ACL for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            /* default entry? */
            if(!tid.netobj.sock_p)
              return -RSBAC_EINVALIDTARGET;
            else
              return rsbac_list_lol_remove(netobj_handle, &tid.netobj.sock_p);
#endif

          default:
            err = -RSBAC_EINVALIDTARGET;
        }
      return(err);
  }

/* rsbac_acl_add_to_acl_entry
 * Add given rights to ACL entry for given target and subject. If entry does
 * not exist, behaviour is exactly like rsbac_acl_set_acl_entry.
 */

int rsbac_acl_add_to_acl_entry     (enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id,
                                           rsbac_acl_rights_vector_t   rights,
                                           rsbac_time_t                ttl)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      rsbac_acl_rights_vector_t               old_rights;
      struct rsbac_acl_entry_desc_t           desc;
      u_long                                  dflags;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_add_to_acl_entry(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (subj_type >= ACLS_NONE)
        return(-RSBAC_EINVALIDVALUE);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_add_to_acl_entry(): called from interrupt!\n");
        }
#endif
      desc.subj_type = subj_type;
      desc.subj_id = subj_id;

      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to file/dir/fifo/symlink ACL for device %02u:%02u, inode %u\n",
                       MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              {
                if(!rsbac_list_get_data(default_fd_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_fd_handle, ttl, &desc, &rights);
              }
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_set_acl_entry(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            /* protect this list */
            list_no = fd_hash(tid.file.inode);
            if(!rsbac_list_lol_exist(device_p->handles[list_no], &tid.file.inode))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_FD_MASK;

                err = rsbac_list_lol_add(device_p->handles[list_no], &tid.file.inode, &mask);
                if(err)
                  {
                    rsbac_read_unlock(&device_list_head.lock, &dflags);
                    return err;
                  }
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(device_p->handles[list_no],
                                               &tid.file.inode,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            err = rsbac_list_lol_subadd_ttl(device_p->handles[list_no],
                                            ttl,
                                            &tid.file.inode,
                                            &desc,
                                            &rights);
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            /* ready. */
            return err;

          case T_DEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to device ACL entry for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            /* default entry? */
            if((tid.dev.type == D_none) && !tid.dev.id)
              {
                if(!rsbac_list_get_data(default_dev_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_dev_handle, ttl, &desc, &rights);
              }
            if(!rsbac_list_lol_exist(dev_handle, &tid.dev))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_DEV_MASK;

                err = rsbac_list_lol_add(dev_handle, &tid.dev, &mask);
                if(err)
                  return err;
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(dev_handle,
                                               &tid.dev,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            return rsbac_list_lol_subadd_ttl(dev_handle,
                                             ttl,
                                             &tid.dev,
                                             &desc,
                                             &rights);

          case T_IPC:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to IPC ACL for type %u\n",
                       tid.ipc.type);
#endif
            /* default entry? */
            if(tid.ipc.type == I_none)
              {
                if(!rsbac_list_get_data(default_ipc_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_ipc_handle, ttl, &desc, &rights);
              }
            else
              return -RSBAC_EINVALIDTARGET;

          case T_SCD:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                {
                  char tmp[80];

                  printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to SCD ACL entry for %s\n",
                         get_acl_scd_type_name(tmp, tid.dev.id));
                }
#endif
            /* default entry? */
            if(tid.scd == AST_none)
              {
                if(!rsbac_list_get_data(default_scd_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_scd_handle, ttl, &desc, &rights);
              }
            if(!rsbac_list_lol_exist(scd_handle, &tid.scd))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_SCD_MASK;

                err = rsbac_list_lol_add(scd_handle, &tid.scd, &mask);
                if(err)
                  return err;
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(scd_handle,
                                               &tid.scd,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            return rsbac_list_lol_subadd_ttl(scd_handle,
                                             ttl,
                                             &tid.scd,
                                             &desc,
                                             &rights);

          case T_USER:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to user ACL for user %u\n",
                       tid.user);
#endif
            /* default entry? */
            if(tid.user == RSBAC_NO_USER)
              {
                if(!rsbac_list_get_data(default_u_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_u_handle, ttl, &desc, &rights);
              }
            else
              return -RSBAC_EINVALIDTARGET;

          case T_PROCESS:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to process ACL for pid %u\n",
                       tid.process);
#endif
            /* default entry? */
            if(!tid.process)
              {
                if(!rsbac_list_get_data(default_p_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_p_handle, ttl, &desc, &rights);
              }
            else
              return -RSBAC_EINVALIDTARGET;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to network device ACL entry for netdev %s\n",
                       tid.netdev);
#endif
            /* default entry? */
            if(!tid.netdev[0])
              {
                if(!rsbac_list_get_data(default_netdev_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_netdev_handle, ttl, &desc, &rights);
              }
            if(!rsbac_list_lol_exist(netdev_handle, &tid.netdev))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETDEV_MASK;

                err = rsbac_list_lol_add(netdev_handle, &tid.netdev, &mask);
                if(err)
                  return err;
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(netdev_handle,
                                               &tid.netdev,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            return rsbac_list_lol_subadd_ttl(netdev_handle,
                                             ttl,
                                             &tid.netdev,
                                             &desc,
                                             &rights);
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to network template NT ACL entry for nettemp_nt %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
              {
                if(!rsbac_list_get_data(default_nettemp_nt_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_nettemp_nt_handle, ttl, &desc, &rights);
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_list_lol_exist(nettemp_nt_handle, &tid.nettemp))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETTEMP_MASK;

                err = rsbac_list_lol_add(nettemp_nt_handle, &tid.nettemp, &mask);
                if(err)
                  return err;
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(nettemp_nt_handle,
                                               &tid.nettemp,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            return rsbac_list_lol_subadd_ttl(nettemp_nt_handle,
                                             ttl,
                                             &tid.nettemp,
                                             &desc,
                                             &rights);
          case T_NETTEMP:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to network template ACL entry for nettemp %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
              {
                return -RSBAC_EINVALIDTARGET;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_list_lol_exist(nettemp_handle, &tid.nettemp))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;

                err = rsbac_list_lol_add(nettemp_handle, &tid.nettemp, &mask);
                if(err)
                  return err;
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(nettemp_handle,
                                               &tid.nettemp,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            return rsbac_list_lol_subadd_ttl(nettemp_handle,
                                             ttl,
                                             &tid.nettemp,
                                             &desc,
                                             &rights);
          case T_NETOBJ:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_add_to_acl_entry(): Adding to network object ACL entry for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            /* default entry? */
            if(!tid.netobj.sock_p)
              {
                if(!rsbac_list_get_data(default_netobj_handle, &desc, &old_rights))
                  rights |= old_rights;
                return rsbac_list_add_ttl(default_netobj_handle, ttl,&desc, &rights);
              }
            if(!rsbac_list_lol_exist(netobj_handle, &tid.netobj.sock_p))
              { /* new acl */
                rsbac_acl_rights_vector_t mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;

                err = rsbac_list_lol_add(netobj_handle, &tid.netobj.sock_p, &mask);
                if(err)
                  return err;
              }
            else
              { /* old entry? */
                if(!rsbac_list_lol_get_subdata(netobj_handle,
                                               &tid.netobj.sock_p,
                                               &desc,
                                               &old_rights))
                  rights |= old_rights;
              }
            return rsbac_list_lol_subadd_ttl(netobj_handle,
                                             ttl,
                                             &tid.netobj.sock_p,
                                             &desc,
                                             &rights);
#endif /* NET_OBJ_PROT */

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  }

/* rsbac_acl_remove_from_acl_entry
 * Remove given rights from ACL entry for given target and subject. If entry does
 * not exist, nothing happens.
 * This function does NOT remove the ACL entry, so removing all rights results in
 * NO rights for this subject/target combination!
 */

int rsbac_acl_remove_from_acl_entry(enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id,
                                           rsbac_acl_rights_vector_t   rights)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      rsbac_acl_rights_vector_t               old_rights;
      struct rsbac_acl_entry_desc_t           desc;
      u_long                                  dflags;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_remove_from_acl_entry(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (subj_type >= ACLS_NONE)
        return(-RSBAC_EINVALIDVALUE);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_remove_from_acl_entry(): called from interrupt!\n");
        }
#endif
      desc.subj_type = subj_type;
      desc.subj_id = subj_id;

      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from file/dir/fifo/symlink ACL for device %02u:%02u, inode %u\n",
                       MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              {
                if(!rsbac_list_get_data(default_fd_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_fd_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_set_acl_entry(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            list_no = fd_hash(tid.file.inode);
            if(!rsbac_list_lol_get_subdata(device_p->handles[list_no],
                                           &tid.file.inode,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                err = rsbac_list_lol_subadd(device_p->handles[list_no],
                                            &tid.file.inode,
                                            &desc,
                                            &old_rights);
              }
            else
              err = 0;
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            return err;

          case T_DEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from device ACL entry for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            /* default entry? */
            if((tid.dev.type == D_none) && !tid.dev.id)
              {
                if(!rsbac_list_get_data(default_dev_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_dev_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            if(!rsbac_list_lol_get_subdata(dev_handle,
                                           &tid.dev,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                return rsbac_list_lol_subadd(dev_handle,
                                             &tid.dev,
                                             &desc,
                                             &old_rights);
              }
            else
              return 0;

          case T_IPC:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from IPC ACL for type %u\n",
                       tid.ipc.type);
#endif
*/
            /* default entry? */
            if(tid.ipc.type == I_none)
              {
                if(!rsbac_list_get_data(default_ipc_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_ipc_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            else
              return -RSBAC_EINVALIDTARGET;

          case T_SCD:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                {
                  char tmp[80];

                  printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from SCD ACL entry for %s\n",
                         get_acl_scd_type_name(tmp, tid.dev.id));
                }
#endif
*/
            /* default entry? */
            if(tid.scd == AST_none)
              {
                if(!rsbac_list_get_data(default_scd_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_scd_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            if(!rsbac_list_lol_get_subdata(scd_handle,
                                           &tid.scd,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                return rsbac_list_lol_subadd(scd_handle,
                                             &tid.scd,
                                             &desc,
                                             &old_rights);
              }
            else
              return 0;

          case T_USER:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from user ACL for user %u\n",
                       tid.user);
#endif
            /* default entry? */
            if(tid.user == RSBAC_NO_USER)
              {
                if(!rsbac_list_get_data(default_u_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_u_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            else
              return -RSBAC_EINVALIDTARGET;

          case T_PROCESS:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from process ACL for pid %u\n",
                       tid.process);
#endif
            /* default entry? */
            if(!tid.process)
              {
                if(!rsbac_list_get_data(default_p_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_p_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            else
              return -RSBAC_EINVALIDTARGET;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from network device ACL entry for netdev %s\n",
                       tid.netdev);
#endif
            /* default entry? */
            if(!tid.netdev[0])
              {
                if(!rsbac_list_get_data(default_netdev_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_netdev_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            if(!rsbac_list_lol_get_subdata(netdev_handle,
                                           &tid.netdev,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                return rsbac_list_lol_subadd(netdev_handle,
                                             &tid.netdev,
                                             &desc,
                                             &old_rights);
              }
            else
              return 0;
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from network template NT ACL entry for nettemp_nt %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
              {
                if(!rsbac_list_get_data(default_nettemp_nt_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_nettemp_nt_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_list_lol_get_subdata(nettemp_nt_handle,
                                           &tid.nettemp,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                return rsbac_list_lol_subadd(nettemp_nt_handle,
                                             &tid.nettemp,
                                             &desc,
                                             &old_rights);
              }
            else
              return 0;
          case T_NETTEMP:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from network template ACL entry for nettemp %u\n",
                       tid.nettemp);
#endif
            /* default entry? */
            if(!tid.nettemp)
              {
                  return -RSBAC_EINVALIDTARGET;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_list_lol_get_subdata(nettemp_handle,
                                           &tid.nettemp,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                return rsbac_list_lol_subadd(nettemp_handle,
                                             &tid.nettemp,
                                             &desc,
                                             &old_rights);
              }
            else
              return 0;
          case T_NETOBJ:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_remove_from_acl_entry(): Removing from network object ACL entry for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            /* default entry? */
            if(!tid.netobj.sock_p)
              {
                if(!rsbac_list_get_data(default_netobj_handle, &desc, &old_rights))
                  {
                    old_rights &= ~rights;
                    return rsbac_list_add(default_netobj_handle, &desc, &old_rights);
                  }
                else
                  return 0;
              }
            if(!rsbac_list_lol_get_subdata(netobj_handle,
                                           &tid.netobj.sock_p,
                                           &desc,
                                           &old_rights))
              {
                old_rights &= ~rights;
                return rsbac_list_lol_subadd(netobj_handle,
                                             &tid.netobj.sock_p,
                                             &desc,
                                             &old_rights);
              }
            else
              return 0;
#endif /* NET_OBJ_PROT */

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  }

/* rsbac_acl_set_mask
 * Set inheritance mask for given target to given rights. If item does
 * not exist, it is created.
 */

int rsbac_acl_set_mask        (enum   rsbac_target_t              target,
                               union  rsbac_target_id_t           tid,
                                      rsbac_acl_rights_vector_t   mask)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      u_long                                  dflags;
    
      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_set_mask(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_set_mask(): called from interrupt!\n");
        }
#endif
      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting file/dir/fifo/symlink inheritance mask for device %02u:%02u, inode %u\n",
                         MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_set_mask(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            list_no = fd_hash(tid.file.inode);
            err = rsbac_list_lol_add(device_p->handles[list_no], &tid.file.inode, &mask);
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            /* ready. */
            return err;

          case T_DEV:
            /* default entry? */
            if(tid.dev.type == D_none)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting device inheritance mask for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            return rsbac_list_lol_add(dev_handle, &tid.dev, &mask);

          case T_SCD:
            /* default entry? */
            if(tid.scd == AST_none)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
              {
                char tmp[80];

                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting SCD inheritance mask for %s\n",
                       get_acl_scd_type_name(tmp, tid.scd));
              }
#endif
            return rsbac_list_lol_add(scd_handle, &tid.scd, &mask);

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
            /* default entry? */
            if(!tid.netdev[0])
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting network device inheritance mask for netdev %s\n",
                       tid.netdev);
#endif
            return rsbac_list_lol_add(netdev_handle, &tid.netdev, &mask);
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
            /* default entry? */
            if(!tid.nettemp)
              {
                return -RSBAC_EINVALIDTARGET;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting network template NT inheritance mask for nettemp %u\n",
                       tid.nettemp);
#endif
            return rsbac_list_lol_add(nettemp_nt_handle, &tid.nettemp, &mask);

          case T_NETTEMP:
            /* default entry? */
            if(!tid.nettemp)
              {
                return -RSBAC_EINVALIDTARGET;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting network template inheritance mask for nettemp %u\n",
                       tid.nettemp);
#endif
            return rsbac_list_lol_add(nettemp_handle, &tid.nettemp, &mask);

          case T_NETOBJ:
            /* default entry? */
            if(!tid.netobj.sock_p)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_set_mask(): Setting network object inheritance mask for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            return rsbac_list_lol_add(netobj_handle, &tid.netobj.sock_p, &mask);
#endif /* NET_OBJ_PROT */

          default:
            err = -RSBAC_EINVALIDTARGET;
        }
      return(err);
  }

/* rsbac_acl_get_mask
 * Get inheritance mask for given target. If item does
 * not exist, default mask is returned.
 */

int rsbac_acl_get_mask        (enum   rsbac_target_t              target,
                               union  rsbac_target_id_t           tid,
                                      rsbac_acl_rights_vector_t * mask_p)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      u_long                                  dflags;
    
      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_get_mask(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_get_mask(): called from interrupt!\n");
        }
#endif
      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_mask(): Getting file/dir/fifo/symlink inheritance mask for device %02u:%02u, inode %u\n",
                         MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_get_mask(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            list_no = fd_hash(tid.file.inode);
            err = rsbac_list_lol_get_data(device_p->handles[list_no], &tid.file.inode, mask_p);
            /* unlock */
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_FD_MASK;
                err = 0;
              }
            /* ready. */
            return err;

          case T_DEV:
            /* default entry? */
            if(tid.dev.type == D_none)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_mask(): Getting device inheritance mask for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            err = rsbac_list_lol_get_data(dev_handle, &tid.dev, mask_p);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_DEV_MASK;
                err = 0;
              }
            /* ready. */
            return err;

          case T_SCD:
            /* default entry? */
            if(tid.scd == AST_none)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
              {
                char tmp[80];

                printk(KERN_DEBUG
                       "rsbac_acl_get_mask(): Getting SCD inheritance mask for %s\n",
                       get_acl_scd_type_name(tmp, tid.scd));
              }
#endif
            err = rsbac_list_lol_get_data(scd_handle, &tid.scd, mask_p);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_SCD_MASK;
                err = 0;
              }
            /* ready. */
            return err;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
            /* default entry? */
            if(!tid.netdev[0])
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG
                       "rsbac_acl_get_mask(): Getting network device inheritance mask for netdev %s\n",
                       tid.netdev);
#endif
            err = rsbac_list_lol_get_data(netdev_handle, &tid.netdev, mask_p);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_NETDEV_MASK;
                err = 0;
              }
            /* ready. */
            return err;
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          case T_NETTEMP_NT:
            /* default entry? */
            if(!tid.nettemp)
              {
                return -RSBAC_EINVALIDTARGET;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG
                       "rsbac_acl_get_mask(): Getting network template NT inheritance mask for nettemp %u\n",
                       tid.nettemp);
#endif
            err = rsbac_list_lol_get_data(nettemp_nt_handle, &tid.nettemp, mask_p);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_NETTEMP_MASK;
                err = 0;
              }
            /* ready. */
            return err;
          case T_NETTEMP:
            /* default entry? */
            if(!tid.nettemp)
              {
                return -RSBAC_EINVALIDTARGET;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG
                       "rsbac_acl_get_mask(): Getting network template inheritance mask for nettemp %u\n",
                       tid.nettemp);
#endif
            err = rsbac_list_lol_get_data(nettemp_handle, &tid.nettemp, mask_p);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_NETOBJ_MASK;
                err = 0;
              }
            /* ready. */
            return err;
          case T_NETOBJ:
            /* default entry? */
            if(!tid.netobj.sock_p)
              {
                return -RSBAC_EINVALIDTARGET;
              }
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG
                       "rsbac_acl_get_mask(): Getting network template inheritance mask for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            err = rsbac_list_lol_get_data(netobj_handle, &tid.netobj.sock_p, mask_p);
            if(err == -RSBAC_ENOTFOUND)
              {
                *mask_p = RSBAC_ACL_DEFAULT_NETOBJ_MASK;
                err = 0;
              }
            /* ready. */
            return err;
#endif

          default:
            err = -RSBAC_EINVALIDTARGET;
        }
      return(err);
  }

/* rsbac_acl_get_rights
 * Get rights from ACL entry for given target and subject.
 * If entry does not exist and inherit is on, inherited rights are used.
 * If there is no parent, the default rights vector for this target type is returned.
 * This function does NOT add role or group rights to user rights!
 */

int rsbac_acl_get_rights       (enum   rsbac_target_t              target,
                                union  rsbac_target_id_t           tid,
                                enum   rsbac_acl_subject_type_t    subj_type,
                                       rsbac_acl_subject_id_t      subj_id,
                                       rsbac_acl_rights_vector_t * rights_p,
                                       boolean                     inherit)
  {
      int err = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      u_long                                  dflags;
      struct rsbac_acl_entry_desc_t           desc;
      rsbac_acl_rights_vector_t               i_rights = 0;
      rsbac_acl_rights_vector_t               mask = -1;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_get_rights(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (!rights_p)
        return(-RSBAC_EINVALIDPOINTER);
      if (subj_type >= ACLS_NONE)
        return(-RSBAC_EINVALIDVALUE);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_get_rights(): called from interrupt!\n");
        }
#endif
      desc.subj_type = subj_type;
      desc.subj_id = subj_id;

      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
              {
                char tmp[20];
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting rights of %s %u for device %02u:%02u, inode %u\n",
                       get_acl_subject_type_name(tmp,subj_type), subj_id, MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
              }
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              {
                if(rsbac_list_get_data(default_fd_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_fd_rights;
                  }
                return 0;
              }
            *rights_p = 0;
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* use loop for inheritance - used to be recursive calls */
            for (;;)
              {
                /* lookup device */
                device_p = acl_lookup_device(tid.file.device);
                if (!device_p)
                  {
                    printk(KERN_WARNING
                           "rsbac_acl_get_rights(): Could not lookup device %02u:%02u!\n",
                           MAJOR(tid.file.device),MINOR(tid.file.device));
                    /* free read lock */
                    rsbac_read_unlock(&device_list_head.lock, &dflags);
                    return(-RSBAC_EINVALIDDEV);
                  }
                list_no = fd_hash(tid.file.inode);
                if(!rsbac_list_lol_get_subdata(device_p->handles[list_no],
                                               &tid.file.inode,
                                               &desc,
                                               &i_rights))
                  {
                    *rights_p |= (i_rights & mask);
                    /* leave loop */
                    break;
                  }
                else
                  if(inherit)
                    {
                      enum rsbac_target_t       parent_target;
                      union rsbac_target_id_t   parent_tid;
                      rsbac_acl_rights_vector_t i_mask;

                      /* get mask to filter through in next round */
                      if(rsbac_list_lol_get_data(device_p->handles[list_no],
                                                 &tid.file.inode,
                                                 &i_mask))
                        {
                          /* no mask found, set default */
                          i_mask = RSBAC_ACL_DEFAULT_FD_MASK;
                        }
                      /* mask into cumulative mask */
                      mask &= i_mask;

                      /* inheritance possible? */
                      if(!rsbac_get_parent(target, tid, &parent_target, &parent_tid))
                        {
                          target = parent_target;
                          tid = parent_tid;
                          /* next round */
                          continue;
                        }
                      else
                        {
                          /* no inheritance possible -> try default_fd_acl */
                          if(!rsbac_list_get_data(default_fd_handle,
                                                  &desc,
                                                  &i_rights))
                            {
                              /* found, use it */
                              *rights_p |= (i_rights & mask);
                            }
                          else
                            {
                              /* last resort: default rights */
                              *rights_p |= (default_fd_rights & mask);
                            }
                        }
                      /* leave loop */
                      break;
                    }
                  else /* do not inherit */
                    {
                      /* last resort: default rights */
                      *rights_p |= default_fd_rights;
                      /* leave loop */
                      break;
                    }
              } /* end of for(;;) inheritance loop */
            /* unprotect */
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            return err;

          case T_DEV:
            /* default entry? */
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting device rights for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            if((tid.dev.type == D_none) && !tid.dev.id)
              {
                if(rsbac_list_get_data(default_dev_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_dev_rights;
                  }
                return 0;
              }
            if(!rsbac_list_lol_get_subdata(dev_handle,
                                           &tid.dev,
                                           &desc,
                                           &i_rights))
              {
                *rights_p |= i_rights;
              }
            else
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(rsbac_list_lol_get_data(dev_handle,
                                           &tid.dev,
                                           &mask))
                  {
                    /* no mask found, set default */
                    mask = RSBAC_ACL_DEFAULT_DEV_MASK;
                  }
                /* try default_dev_acl */
                if(!rsbac_list_get_data(default_dev_handle, &desc, rights_p))
                  {
                    *rights_p &= mask;
                  }
                else
                  {
                    /* last resort: default rights */
                    *rights_p = default_dev_rights & mask;
                  }
              }
            return 0;

          case T_IPC:
            
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting IPC rights for type %u\n",
                       tid.ipc.type);
#endif
            /* Use default ACL */
            if(rsbac_list_get_data(default_ipc_handle, &desc, rights_p))
              {
                /* last resort: default rights */
                *rights_p = default_ipc_rights;
              }
            return 0;

          case T_SCD:
            /* default entry? */
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
              {
                char tmp[80];
                printk(KERN_DEBUG
                       "rsbac_acl_get_rights(): Getting SCD rights for %s\n",
                       get_acl_scd_type_name(tmp, tid.scd));
              }
#endif
            if(tid.scd == AST_none)
              {
                if(rsbac_list_get_data(default_scd_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_scd_rights;
                  }
                return 0;
              }
            if(!rsbac_list_lol_get_subdata(scd_handle,
                                           &tid.scd,
                                           &desc,
                                           &i_rights))
              {
                *rights_p |= i_rights;
              }
            else
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(rsbac_list_lol_get_data(scd_handle,
                                           &tid.scd,
                                           &mask))
                  {
                    /* no mask found, set default */
                    mask = RSBAC_ACL_DEFAULT_SCD_MASK;
                  }
                /* try default_dev_acl */
                if(!rsbac_list_get_data(default_scd_handle, &desc, rights_p))
                  {
                    *rights_p &= mask;
                  }
                else
                  {
                    /* last resort: default rights */
                    *rights_p = default_scd_rights & mask;
                  }
              }
            return 0;

          case T_USER:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting user rights for user %u\n",
                       tid.user);
#endif
            /* Use default entry */
            if(rsbac_list_get_data(default_u_handle, &desc, rights_p))
              {
                /* last resort: default rights */
                *rights_p = default_u_rights;
              }
            return 0;

          case T_PROCESS:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting process rights for pid %u\n",
                       tid.process);
#endif
*/
            /* Use default entry */
            if(rsbac_list_get_data(default_p_handle, &desc, rights_p))
              {
                /* last resort: default rights */
                *rights_p = default_p_rights;
              }
            return 0;

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
          case T_NETDEV:
            /* default entry? */
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting network device rights for netdev %s\n",
                       tid.netdev);
#endif
            if(!tid.netdev[0])
              {
                if(rsbac_list_get_data(default_netdev_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_netdev_rights;
                  }
                return 0;
              }
            if(!rsbac_list_lol_get_subdata(netdev_handle,
                                           &tid.netdev,
                                           &desc,
                                           &i_rights))
              {
                *rights_p |= i_rights;
              }
            else
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(rsbac_list_lol_get_data(netdev_handle,
                                           &tid.netdev,
                                           &mask))
                  {
                    /* no mask found, set default */
                    mask = RSBAC_ACL_DEFAULT_NETDEV_MASK;
                  }
                /* try default_dev_acl */
                if(!rsbac_list_get_data(default_netdev_handle, &desc, rights_p))
                  {
                    *rights_p &= mask;
                  }
                else
                  {
                    /* last resort: default rights */
                    *rights_p = default_netdev_rights & mask;
                  }
              }
            return 0;
#endif

#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
          /* rights to template itself */
          case T_NETTEMP_NT:
            /* default entry? */
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting network template NT rights for nettemp %u\n",
                       tid.nettemp);
#endif
            if(!tid.nettemp)
              {
                if(rsbac_list_get_data(default_nettemp_nt_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_nettemp_nt_rights;
                  }
                return 0;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_list_lol_get_subdata(nettemp_nt_handle,
                                           &tid.nettemp,
                                           &desc,
                                           &i_rights))
              {
                *rights_p |= i_rights;
              }
            else
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(rsbac_list_lol_get_data(nettemp_nt_handle,
                                           &tid.nettemp,
                                           &mask))
                  {
                    /* no mask found, set default */
                    mask = RSBAC_ACL_DEFAULT_NETTEMP_MASK;
                  }
                /* try default_dev_acl */
                if(!rsbac_list_get_data(default_nettemp_nt_handle, &desc, rights_p))
                  {
                    *rights_p &= mask;
                  }
                else
                  {
                    /* last resort: default rights */
                    *rights_p = default_nettemp_nt_rights & mask;
                  }
              }
            return 0;

          /* rights to netobjs fitting this template */
          case T_NETTEMP:
            /* default entry? */
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting network template rights for nettemp %u\n",
                       tid.nettemp);
#endif
            if(!tid.nettemp)
              {
                if(rsbac_list_get_data(default_netobj_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_netobj_rights;
                  }
                return 0;
              }
            if(!rsbac_net_template_exist(tid.nettemp))
                return -RSBAC_EINVALIDTARGET;
            if(!rsbac_list_lol_get_subdata(nettemp_handle,
                                           &tid.nettemp,
                                           &desc,
                                           &i_rights))
              {
                *rights_p |= i_rights;
              }
            else
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(rsbac_list_lol_get_data(nettemp_handle,
                                           &tid.nettemp,
                                           &mask))
                  {
                    /* no mask found, set default */
                    mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;
                  }
                /* try default_dev_acl */
                if(!rsbac_list_get_data(default_netobj_handle, &desc, rights_p))
                  {
                    *rights_p &= mask;
                  }
                else
                  {
                    /* last resort: default rights */
                    *rights_p = default_netobj_rights & mask;
                  }
              }
            return 0;

          case T_NETOBJ:
            /* default entry? */
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_rights(): Getting network object rights for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            if(!tid.nettemp)
              {
                if(rsbac_list_get_data(default_netobj_handle, &desc, rights_p))
                  {
                    /* last resort: default rights */
                    *rights_p = default_netobj_rights;
                  }
                return 0;
              }
            if(!rsbac_list_lol_get_subdata(netobj_handle,
                                           &tid.netobj.sock_p,
                                           &desc,
                                           &i_rights))
              {
                *rights_p |= i_rights;
              }
            else
              {
                rsbac_acl_rights_vector_t mask;
                rsbac_net_temp_id_t temp = 0;

                /* get mask to filter through */
                if(rsbac_list_lol_get_data(nettemp_handle,
                                           &temp,
                                           &mask))
                  {
                    /* no mask found, set default */
                    mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;
                  }
                /* try nettemp_acl */
                rsbac_net_lookup_templates(tid.netobj,
                                           &temp,
                                           NULL);

                if(   temp
                   && !rsbac_list_lol_get_subdata(nettemp_handle,
                                                  &temp,
                                                  &desc,
                                                  &i_rights))
                  {
                    *rights_p |= i_rights;
                  }
                else
                  {
                    /* get mask to filter through */
                    if(   temp
                       && rsbac_list_lol_get_data(nettemp_handle,
                                                  &temp,
                                                  &mask))
                      {
                        /* no mask found, set default */
                        mask = RSBAC_ACL_DEFAULT_NETOBJ_MASK;
                      }
                    /* try default_netobj_acl */
                    if(!rsbac_list_get_data(default_netobj_handle, &desc, rights_p))
                      {
                        *rights_p &= mask;
                      }
                    else
                      {
                        /* last resort: default rights */
                        *rights_p = default_netobj_rights & mask;
                      }
                  }
              }
            return 0;
#endif /* NET_OBJ_PROT */

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  }

/* rsbac_acl_get_single_right
 * Show, whether individual right is set for given target and subject.
 * If right is not set, it is checked at all parents, unless it has been
 * masked out. (Special case SUPERVISOR: unless
 * CONFIG_RSBAC_ACL_SUPER_FILTER is set *and* supervisor has been masked out)
 */

int rsbac_acl_get_single_right (enum   rsbac_target_t              target,
                                union  rsbac_target_id_t           tid,
                                enum   rsbac_acl_subject_type_t    subj_type,
                                       rsbac_acl_subject_id_t      subj_id,
                                enum   rsbac_adf_request_t         right,
                                       boolean                   * result)
  {
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      u_long                                  dflags;
      rsbac_acl_rights_vector_t               i_rvec;
      rsbac_acl_rights_vector_t               i_rights;
      struct rsbac_acl_entry_desc_t           desc;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_get_single_right(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (!result)
        return(-RSBAC_EINVALIDPOINTER);
      if (   (subj_type >= ACLS_NONE)
          || (right >= ACLR_NONE)
         )
        return(-RSBAC_EINVALIDVALUE);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_get_single_right(): called from interrupt!\n");
        }
#endif
      i_rvec = (rsbac_acl_rights_vector_t) 1 << right;

      desc.subj_type = subj_type;
      desc.subj_id = subj_id;

      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Checking right of subject %u,%u for device %02u:%02u, inode %u\n",
                         subj_type, subj_id, MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              {
                if(!rsbac_list_get_data(default_fd_handle, &desc, &i_rights))
                  {
                    if(i_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
                else
                  {
                    if(default_fd_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* use loop for inheritance - used to be recursive calls */
            for (;;)
              {
                /* lookup device */
                device_p = acl_lookup_device(tid.file.device);
                if (!device_p)
                  {
                    printk(KERN_WARNING
                           "rsbac_acl_get_single_right(): Could not lookup device!\n");
                    /* free read lock */
                    rsbac_read_unlock(&device_list_head.lock, &dflags);
                    return(-RSBAC_EINVALIDDEV);
                  }
                list_no = fd_hash(tid.file.inode);
                if(   !rsbac_list_lol_get_subdata(device_p->handles[list_no],
                                                  &tid.file.inode,
                                                  &desc,
                                                  &i_rights)
                   && (i_rights & i_rvec)
                  )
                  {
                    rsbac_read_unlock(&device_list_head.lock, &dflags);
                    *result = TRUE;
                    return 0;
                  }

                {
                  enum rsbac_target_t       parent_target;
                  union rsbac_target_id_t   parent_tid;

                  #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
                  if(right != ACLR_SUPERVISOR)
                  #endif
                    {
                      rsbac_acl_rights_vector_t mask;

                      /* get mask to filter through */
                      if(   !rsbac_list_lol_get_data(device_p->handles[list_no],
                                                     &tid.file.inode,
                                                     &mask)
                         && !(mask & i_rvec)
                        )
                        {
                          rsbac_read_unlock(&device_list_head.lock, &dflags);
                          *result = FALSE;
                          return 0;
                        }
                    }

                  /* inheritance possible? */
                  if(!rsbac_get_parent(target, tid, &parent_target, &parent_tid))
                    {
                      target = parent_target;
                      tid = parent_tid;
                      continue;
                    }
                  else
                    {
                      /* no inheritance possible -> try default_fd_acl */
                      if(   !rsbac_list_get_data(default_fd_handle,
                                                 &desc,
                                                 &i_rights)
                         && (i_rights & i_rvec)
                        )
                        {
                          *result = TRUE;
                        }
                      else
                        {
                          if(default_fd_rights & i_rvec)
                            *result = TRUE;
                          else
                            *result = FALSE;
                        }
                      /* free access to device_list_head - see above */
                      rsbac_read_unlock(&device_list_head.lock, &dflags);
                      return 0;
                    }
                }
              } /* end of for(;;) for inheritance */

          case T_DEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting right for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
            if((tid.dev.type == D_none) && !tid.dev.id)
              {
                if(!rsbac_list_get_data(default_dev_handle, &desc, &i_rights))
                  {
                    if(i_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
                else
                  {
                    if(default_dev_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }

            if(   !rsbac_list_lol_get_subdata(dev_handle,
                                              &tid.dev,
                                              &desc,
                                              &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
                return 0;
              }
            #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
            if(right != ACLR_SUPERVISOR)
            #endif
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(   !rsbac_list_lol_get_data(dev_handle,
                                               &tid.dev,
                                               &mask)
                   && !(mask & i_rvec)
                  )
                  {
                    *result = FALSE;
                    return 0;
                  }
              }

            /* no inheritance possible -> try default acl */
            if(   !rsbac_list_get_data(default_dev_handle,
                                       &desc,
                                       &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
              }
            else
              {
                if(default_dev_rights & i_rvec)
                  *result = TRUE;
                else
                  *result = FALSE;
              }
            return 0;

          case T_IPC:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting right for type %u\n",
                       tid.ipc.type);
#endif
            /* Use default entry */
            if(!rsbac_list_get_data(default_ipc_handle, &desc, &i_rights))
              {
                if(i_rights & i_rvec)
                  {
                    *result = TRUE;
                    return 0;
                  }
                else
                  {
                    *result = FALSE;
                    return 0;
                  }
              }
            else
              {
                if(default_ipc_rights & i_rvec)
                  {
                    *result = TRUE;
                    return 0;
                  }
                else
                  {
                    *result = FALSE;
                    return 0;
                  }
              }

          case T_SCD:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                {
                  char tmp[80];

                  printk(KERN_DEBUG
                         "rsbac_acl_get_single_right(): Getting right for SCD %s\n",
                         get_acl_scd_type_name(tmp, tid.scd));
                }
#endif
            if(tid.scd == AST_none)
              {
                if(!rsbac_list_get_data(default_scd_handle, &desc, &i_rights))
                  {
                    if(i_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
                else
                  {
                    if(default_scd_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }

            if(   !rsbac_list_lol_get_subdata(scd_handle,
                                              &tid.scd,
                                              &desc,
                                              &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
                return 0;
              }
            #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
            if(right != ACLR_SUPERVISOR)
            #endif
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(   !rsbac_list_lol_get_data(scd_handle,
                                               &tid.scd,
                                               &mask)
                   && !(mask & i_rvec)
                  )
                  {
                    *result = FALSE;
                    return 0;
                  }
              }

            /* no inheritance possible -> try default acl */
            if(   !rsbac_list_get_data(default_scd_handle,
                                       &desc,
                                       &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
              }
            else
              {
                if(default_scd_rights & i_rvec)
                  *result = TRUE;
                else
                  *result = FALSE;
              }
            return 0;

          case T_USER:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting user right for user %u\n",
                       tid.user);
#endif
            /* Use default entry */
            if(!rsbac_list_get_data(default_u_handle, &desc, &i_rights))
              {
                if(i_rights & i_rvec)
                  {
                    *result = TRUE;
                    return 0;
                  }
                else
                  {
                    *result = FALSE;
                    return 0;
                  }
              }
            else
              {
                if(default_u_rights & i_rvec)
                  {
                    *result = TRUE;
                    return 0;
                  }
                else
                  {
                    *result = FALSE;
                    return 0;
                  }
              }

          case T_PROCESS:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting process right for pid %u\n",
                       tid.process);
#endif
            /* Use default entry */
            if(!rsbac_list_get_data(default_p_handle, &desc, &i_rights))
              {
                if(i_rights & i_rvec)
                  {
                    *result = TRUE;
                    return 0;
                  }
                else
                  {
                    *result = FALSE;
                    return 0;
                  }
              }
            else
              {
                if(default_p_rights & i_rvec)
                  {
                    *result = TRUE;
                    return 0;
                  }
                else
                  {
                    *result = FALSE;
                    return 0;
                  }
              }

#if defined(CONFIG_RSBAC_ACL_NET_DEV_PROT)
          case T_NETDEV:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting right for netdev %s\n",
                       tid.netdev);
#endif
            if(!tid.netdev[0])
              {
                if(!rsbac_list_get_data(default_netdev_handle, &desc, &i_rights))
                  {
                    if(i_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
                else
                  {
                    if(default_netdev_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }

            if(   !rsbac_list_lol_get_subdata(netdev_handle,
                                              &tid.netdev,
                                              &desc,
                                              &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
                return 0;
              }
            #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
            if(right != ACLR_SUPERVISOR)
            #endif
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(   !rsbac_list_lol_get_data(netdev_handle,
                                               &tid.netdev,
                                               &mask)
                   && !(mask & i_rvec)
                  )
                  {
                    *result = FALSE;
                    return 0;
                  }
              }

            /* no inheritance possible -> try default acl */
            if(   !rsbac_list_get_data(default_netdev_handle,
                                       &desc,
                                       &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
              }
            else
              {
                if(default_netdev_rights & i_rvec)
                  *result = TRUE;
                else
                  *result = FALSE;
              }
            return 0;
#endif

#if defined(CONFIG_RSBAC_ACL_NET_OBJ_PROT)
          case T_NETTEMP_NT:
          case T_NETTEMP:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting right for nettemp %u\n",
                       tid.nettemp);
#endif
            if(!tid.nettemp)
              {
                if(!rsbac_list_get_data(default_nettemp_nt_handle, &desc, &i_rights))
                  {
                    if(i_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
                else
                  {
                    if(default_nettemp_nt_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }

            /* There should be no template, which is to be created, so skip nettemp_nt list */
            if(right != R_CREATE)
              {
                if(!rsbac_net_template_exist(tid.nettemp))
                   return FALSE;
                if(   !rsbac_list_lol_get_subdata(nettemp_nt_handle,
                                                  &tid.nettemp,
                                                  &desc,
                                                  &i_rights)
                   && (i_rights & i_rvec)
                  )
                  {
                    *result = TRUE;
                    return 0;
                  }
                #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
                if(right != ACLR_SUPERVISOR)
                #endif
                  {
                    rsbac_acl_rights_vector_t mask;

                    /* get mask to filter through */
                    if(   !rsbac_list_lol_get_data(nettemp_nt_handle,
                                                   &tid.nettemp,
                                                   &mask)
                       && !(mask & i_rvec)
                      )
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }

            /* no inheritance possible -> try default acl */
            if(   !rsbac_list_get_data(default_nettemp_nt_handle,
                                       &desc,
                                       &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
              }
            else
              {
                if(default_nettemp_nt_rights & i_rvec)
                  *result = TRUE;
                else
                  *result = FALSE;
              }
            return 0;

          case T_NETOBJ:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_single_right(): Getting right for netobj %p\n",
                       tid.netobj.sock_p);
#endif
            if(!tid.netobj.sock_p)
              {
                if(!rsbac_list_get_data(default_netobj_handle, &desc, &i_rights))
                  {
                    if(i_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
                else
                  {
                    if(default_netobj_rights & i_rvec)
                      {
                        *result = TRUE;
                        return 0;
                      }
                    else
                      {
                        *result = FALSE;
                        return 0;
                      }
                  }
              }

            if(   !rsbac_list_lol_get_subdata(netobj_handle,
                                              &tid.netobj.sock_p,
                                              &desc,
                                              &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
                return 0;
              }
            #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
            if(right != ACLR_SUPERVISOR)
            #endif
              {
                rsbac_acl_rights_vector_t mask;

                /* get mask to filter through */
                if(   !rsbac_list_lol_get_data(netobj_handle,
                                               &tid.netobj.sock_p,
                                               &mask)
                   && !(mask & i_rvec)
                  )
                  {
                    *result = FALSE;
                    return 0;
                  }
              }
            /* Try net template */
            {
              rsbac_net_temp_id_t temp = 0;

              rsbac_net_lookup_templates(tid.netobj,
                                         &temp,
                                         NULL);
              if(   temp
                 && !rsbac_list_lol_get_subdata(nettemp_handle,
                                                &temp,
                                                &desc,
                                                &i_rights)
                 && (i_rights & i_rvec)
                )
                {
                  *result = TRUE;
                  return 0;
                }
              #ifndef CONFIG_RSBAC_ACL_SUPER_FILTER
              if(right != ACLR_SUPERVISOR)
              #endif
                {
                  rsbac_acl_rights_vector_t mask;

                  /* get mask from template to filter through */
                  if(   !rsbac_list_lol_get_data(nettemp_handle,
                                                 &temp,
                                                 &mask)
                     && !(mask & i_rvec)
                    )
                    {
                      *result = FALSE;
                      return 0;
                    }
                }
            }

            /* no inheritance possible -> try default acl */
            if(   !rsbac_list_get_data(default_netobj_handle,
                                       &desc,
                                       &i_rights)
               && (i_rights & i_rvec)
              )
              {
                *result = TRUE;
              }
            else
              {
                if(default_netobj_rights & i_rvec)
                  *result = TRUE;
                else
                  *result = FALSE;
              }
            return 0;
#endif /* NET_OBJ_PROT */

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  }

/*************************************************
 * rsbac_acl_get_tlist
 * Get subjects from ACL entries for given target.
 */

int rsbac_acl_get_tlist       (enum   rsbac_target_t            target,
                               union  rsbac_target_id_t         tid,
                               struct rsbac_acl_entry_t      ** entry_pp,
                                      rsbac_time_t           ** ttl_pp)
  {
      int count = 0;
      int list_no;
      struct rsbac_acl_device_list_item_t   * device_p;
      u_long                                  dflags;

      if (!rsbac_is_initialized())
        {
          printk(KERN_WARNING "rsbac_acl_get_tlist(): RSBAC not initialized\n");
          return(-RSBAC_ENOTINITIALIZED);
        }
      if (!entry_pp)
        return(-RSBAC_EINVALIDPOINTER);
#ifdef CONFIG_RSBAC_DEBUG
      if (in_interrupt())
        {
          printk(KERN_WARNING "rsbac_acl_get_tlist(): called from interrupt!\n");
        }
#endif
      switch (target)
        {
          case T_FILE:
          case T_DIR:
          case T_FIFO:
          case T_SYMLINK:
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for device %02u:%02u, inode %u\n",
                       MAJOR(tid.file.device), MINOR(tid.file.device), tid.file.inode);
#endif
            /* default entry? */
            if(!tid.file.device && !tid.file.inode && !tid.file.dentry_p)
              return rsbac_list_get_all_items_ttl(default_fd_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            /* wait for read access to device_list_head */
            rsbac_read_lock(&device_list_head.lock, &dflags);
            /* OK, go on */
            /* lookup device */
            device_p = acl_lookup_device(tid.file.device);
            if (!device_p)
              {
                printk(KERN_WARNING
                       "rsbac_acl_get_tlist(): Could not lookup device!\n");
                /* free read lock */
                rsbac_read_unlock(&device_list_head.lock, &dflags);
                return(-RSBAC_EINVALIDDEV);
              }
            /* protect this list */
            list_no = fd_hash(tid.file.inode);
            count = rsbac_list_lol_get_all_subitems_ttl(device_p->handles[list_no],
                                                        &tid.file.inode,
                                                        (void **) entry_pp,
                                                        ttl_pp);
            rsbac_read_unlock(&device_list_head.lock, &dflags);
            /* ready. */
            return count;

          case T_DEV:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for dev %c %02u:%02u\n",
                       'B'+tid.dev.type,
                       MAJOR(tid.dev.id),
                       MINOR(tid.dev.id));
#endif
*/
            if((tid.dev.type == D_none) && !tid.dev.id)
              return rsbac_list_get_all_items_ttl(default_dev_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return rsbac_list_lol_get_all_subitems_ttl(dev_handle,
                                                         &tid.dev,
                                                         (void **) entry_pp,
                                                         ttl_pp);

          case T_IPC:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for IPC type %u\n",
                       tid.ipc.type);
#endif
*/
            /* default entry? */
            if(tid.ipc.type == I_none)
              return rsbac_list_get_all_items_ttl(default_ipc_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return 0;

          case T_SCD:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                {
                  char tmp[80];

                  printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for SCD %s\n",
                         get_acl_scd_type_name(tmp, tid.scd));
                }
#endif
*/
            if(tid.scd == AST_none)
              return rsbac_list_get_all_items_ttl(default_scd_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return rsbac_list_lol_get_all_subitems_ttl(scd_handle,
                                                         &tid.scd,
                                                         (void **) entry_pp,
                                                         ttl_pp);

          case T_USER:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for pid %u\n",
                       tid.process);
#endif
*/
            /* default entry? */
            if(tid.user == RSBAC_NO_USER)
              return rsbac_list_get_all_items_ttl(default_u_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return 0;

          case T_PROCESS:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for pid %u\n",
                       tid.process);
#endif
*/
            /* default entry? */
            if(!tid.process)
              return rsbac_list_get_all_items_ttl(default_p_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return 0;

#if defined(CONFIG_RSBAC_ACL_NET_DEV_PROT)
          case T_NETDEV:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for netdev %s\n",
                       tid.netdev);
#endif
*/
            if(!tid.netdev[0])
              return rsbac_list_get_all_items_ttl(default_netdev_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return rsbac_list_lol_get_all_subitems_ttl(netdev_handle,
                                                         &tid.netdev,
                                                         (void **) entry_pp,
                                                         ttl_pp);
#endif

#if defined(CONFIG_RSBAC_ACL_NET_OBJ_PROT)
          case T_NETTEMP_NT:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for nettemp_nt %u\n",
                       tid.nettemp);
#endif
*/
            if(!tid.nettemp)
              return rsbac_list_get_all_items_ttl(default_nettemp_nt_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            if(!rsbac_net_template_exist(tid.nettemp))
              return -RSBAC_EINVALIDTARGET;
            return rsbac_list_lol_get_all_subitems_ttl(nettemp_nt_handle,
                                                       &tid.nettemp,
                                                       (void **) entry_pp,
                                                       ttl_pp);

          case T_NETTEMP:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for nettemp %u\n",
                       tid.nettemp);
#endif
*/
            if(!tid.nettemp)
              return -RSBAC_EINVALIDTARGET;
            if(!rsbac_net_template_exist(tid.nettemp))
              return -RSBAC_EINVALIDTARGET;
            return rsbac_list_lol_get_all_subitems_ttl(nettemp_handle,
                                                       &tid.nettemp,
                                                       (void **) entry_pp,
                                                       ttl_pp);

          case T_NETOBJ:
/*
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_ds_acl)
                printk(KERN_DEBUG "rsbac_acl_get_tlist(): Getting tlist for netobj %p\n",
                       tid.netobj.sock_p);
#endif
*/
            if(!tid.nettemp)
              return rsbac_list_get_all_items_ttl(default_netobj_handle,
                                                  (void **) entry_pp,
                                                  ttl_pp);
            else
              return rsbac_list_lol_get_all_subitems_ttl(netobj_handle,
                                                         &tid.netobj.sock_p,
                                                         (void **) entry_pp,
                                                         ttl_pp);
#endif /* NET_OBJ_PROT */

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  }

/* Remove a subject from all acls (but not from group memberships, see remove_user) */
int rsbac_acl_remove_subject(struct rsbac_acl_entry_desc_t desc)
  {
    struct rsbac_acl_device_list_item_t   * device_p;
    u_long dflags;
    u_int i;

    if(desc.subj_type >= ACLS_NONE)
      return -RSBAC_EINVALIDVALUE;

    /* remove from default ACLs */
    rsbac_list_remove(default_fd_handle, &desc);
    rsbac_list_remove(default_dev_handle, &desc);
    rsbac_list_remove(default_ipc_handle, &desc);
    rsbac_list_remove(default_scd_handle, &desc);
    rsbac_list_remove(default_u_handle, &desc);
    rsbac_list_remove(default_p_handle, &desc);
#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    rsbac_list_remove(default_netdev_handle, &desc);
#endif
#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    rsbac_list_remove(default_nettemp_nt_handle, &desc);
    rsbac_list_remove(default_netobj_handle, &desc);
#endif

    /* protect device list */
    rsbac_read_lock(&device_list_head.lock, &dflags);
    device_p = device_list_head.head;
    while(device_p)
      {
        for(i=0; i<RSBAC_ACL_NR_FD_LISTS; i++)
          {
            rsbac_list_lol_subremove_from_all(device_p->handles[i],
                                              &desc);
          }
        device_p = device_p->next;
      }
    /* unprotect device list */
    rsbac_read_unlock(&device_list_head.lock, &dflags);

    /* dev list */
    rsbac_list_lol_subremove_from_all(dev_handle,
                                      &desc);

    /* scd list */
    rsbac_list_lol_subremove_from_all(scd_handle,
                                      &desc);

#ifdef CONFIG_RSBAC_ACL_NET_DEV_PROT
    /* netdev list */
    rsbac_list_lol_subremove_from_all(netdev_handle,
                                      &desc);
#endif
#ifdef CONFIG_RSBAC_ACL_NET_OBJ_PROT
    rsbac_list_lol_subremove_from_all(nettemp_nt_handle,
                                      &desc);
    rsbac_list_lol_subremove_from_all(nettemp_handle,
                                      &desc);
    rsbac_list_lol_subremove_from_all(netobj_handle,
                                      &desc);
#endif

    return 0;
  }

/* add a group with new id and fill this id into *group_id_p */
/* if old content of group_id_p is 0, make new id, else try given id */
int rsbac_acl_add_group(rsbac_uid_t owner, enum rsbac_acl_group_type_t type, char * name,
                        rsbac_acl_group_id_t * group_id_p)
  {
    struct rsbac_acl_group_entry_t entry;
           int                     err=0;

    if(type >= ACLG_NONE)
      return -RSBAC_EINVALIDVALUE;
    if(!name || !group_id_p)
      return -RSBAC_EINVALIDPOINTER;
    entry.owner = owner;
    entry.type = type;
    strncpy(entry.name, name, RSBAC_ACL_GROUP_NAMELEN-1);
    entry.name[RSBAC_ACL_GROUP_NAMELEN-1] = 0;
    if(!*group_id_p)
      {
        /* step new group counter */
        group_last_new++;
        /* Just in case the counter has wrapped. It is almost impossible that all IDs are in use. */
        while(!group_last_new || rsbac_list_exist(group_handle, &group_last_new))
          group_last_new++;

        entry.id = group_last_new;
      }
    else
      {
        if(rsbac_list_exist(group_handle, group_id_p))
          {
            return(-RSBAC_EEXISTS);
          }
        else
          entry.id = *group_id_p;
      }
    if(rsbac_list_add(group_handle, &entry.id, &entry))
      err = -RSBAC_ECOULDNOTADDITEM;
    else
      {
        *group_id_p = entry.id;
      }
    return(err);
  }

int rsbac_acl_change_group(     rsbac_acl_group_id_t     id,
                                rsbac_uid_t              owner,
                           enum rsbac_acl_group_type_t   type,
                                char                   * name)
  {
    struct rsbac_acl_group_entry_t       entry;

    if(!id)
      return -RSBAC_EINVALIDVALUE;
    if(!rsbac_list_exist(group_handle, &id))
      return(-RSBAC_ENOTFOUND);
    entry.id = id;
    entry.owner = owner;
    entry.type = type;
    strncpy(entry.name, name, RSBAC_ACL_GROUP_NAMELEN);
    entry.name[RSBAC_ACL_GROUP_NAMELEN-1] = 0;
    return rsbac_list_add(group_handle, &entry.id, &entry);
  }

int rsbac_acl_remove_group(rsbac_acl_group_id_t id)
  {
           int                     err=0;

    if(!id)
      return -RSBAC_EINVALIDVALUE;

    err = rsbac_list_remove(group_handle, &id);
    if(!err)
      {
        struct rsbac_acl_entry_desc_t           desc;

        /* cleanup group memberships */
        rsbac_list_lol_subremove_from_all(gm_handle,
                                          &id);
        desc.subj_type = ACLS_GROUP;
        desc.subj_id = id;
        err = rsbac_acl_remove_subject(desc);
      }
    return(err);
  }

int rsbac_acl_get_group_entry(rsbac_acl_group_id_t group, struct rsbac_acl_group_entry_t * entry_p)
  {
    if(!group)
      return -RSBAC_EINVALIDVALUE;
    if(!entry_p)
      return -RSBAC_EINVALIDPOINTER;
    return rsbac_list_get_data(group_handle, &group, entry_p);
  }

int rsbac_acl_list_groups(rsbac_uid_t owner,
                          boolean include_global,
                          struct rsbac_acl_group_entry_t ** entry_pp)
  {
    long count;
    struct rsbac_acl_group_entry_t * local_entry_p;

    if(!entry_pp)
      return -RSBAC_EINVALIDPOINTER;
    count = rsbac_list_get_all_data(group_handle, (void **) &local_entry_p);
    if(count > 0)
      {
        long i;
        long rescount = 0;

        *entry_pp = vmalloc(count * sizeof(**entry_pp));
        if(!*entry_pp)
          {
            vfree(local_entry_p);
            return -RSBAC_ENOMEM;
          }
        for(i=0; i<count; i++)
          {
            if(   (local_entry_p[i].owner == owner)
               || (   include_global
                   && (local_entry_p[i].type == ACLG_GLOBAL)
                  )
              )
              {
                memcpy(&(*entry_pp)[rescount], &local_entry_p[i], sizeof(local_entry_p[i]));
                rescount++;
              }
          }
        vfree(local_entry_p);
        count = rescount;
      }
    return count;
  }

/* check group existence */
boolean rsbac_acl_group_exist(rsbac_acl_group_id_t group)
  {
    if(!group)
      return TRUE;
    return rsbac_list_exist(group_handle, &group);
  }

int rsbac_acl_add_group_member(rsbac_acl_group_id_t group, rsbac_uid_t user, rsbac_time_t ttl)
  {
           int                           err=0;

    if(!group)
      return -RSBAC_EINVALIDVALUE;
    if(!rsbac_list_exist(group_handle, &group))
      return -RSBAC_EINVALIDVALUE;

    if(!rsbac_list_lol_exist(gm_handle, &user))
      {
        err = rsbac_list_lol_add(gm_handle, &user, NULL);
        if(err)
          return err;
      }
    return rsbac_list_lol_subadd_ttl(gm_handle, ttl, &user, &group, NULL);
  }

int rsbac_acl_remove_group_member(rsbac_acl_group_id_t group, rsbac_uid_t user)
  {
    int err;

    if(!group)
      return -RSBAC_EINVALIDVALUE;
    if(!rsbac_list_exist(group_handle, &group))
      return -RSBAC_EINVALIDVALUE;

    err = rsbac_list_lol_subremove(gm_handle, &user, &group);
    /* cleanup empty gm items */
    if(   !err
       && !rsbac_list_lol_subcount(gm_handle, &user)
      )
      err = rsbac_list_lol_remove(gm_handle, &user);

    return err;
  }

/* check membership */
boolean rsbac_acl_group_member(rsbac_acl_group_id_t group, rsbac_uid_t user)
  {
    return rsbac_list_lol_subexist(gm_handle, &user, &group);
  }

/* build vmalloc'd array of all group memberships of the given user */
/* returns number of groups or negative error */
/* Attention: memory deallocation with vfree (if result > 0) must be done by caller! */
int rsbac_acl_get_user_groups(rsbac_uid_t user,
                              rsbac_acl_group_id_t ** group_pp,
                              rsbac_time_t ** ttl_pp)
  {
    return rsbac_list_lol_get_all_subdesc_ttl(gm_handle,
                                              &user,
                                              (void **) group_pp,
                                              ttl_pp);
  }

/* Returns number of members or negative error */
int rsbac_acl_get_group_members(rsbac_acl_group_id_t group,
                                rsbac_uid_t user_array[],
                                rsbac_time_t ttl_array[],
                                int maxnum)
  {
    long desc_count;
    long i;
    rsbac_uid_t * user_p;
    int err = 0;

    if(!group || (maxnum <= 0))
      return -RSBAC_EINVALIDVALUE;
    if(!rsbac_list_exist(group_handle, &group))
      return -RSBAC_EINVALIDVALUE;
    if(!user_array)
      return -RSBAC_EINVALIDPOINTER;

    /* traverse group memberships */
    desc_count = rsbac_list_lol_get_all_desc(gm_handle, (void **) &user_p);
    if(desc_count > 0)
      {
        rsbac_time_t ttl;

        for(i=0; i<desc_count; i++)
          {
            if(!rsbac_list_lol_get_subdata_ttl(gm_handle, &ttl, &user_p[i], &group, NULL))
              {
                user_array[err] = user_p[i];
                if(ttl_array)
                  ttl_array[err] = ttl;
                err++;
                if(err >= maxnum)
                  break;
              }
          }
        vfree(user_p);
      }
    return(err);
  }

/********************************************/
/* remove user from all groups and all ACLs */
int rsbac_acl_remove_user(rsbac_uid_t user)
  {
           u_long i;
    struct rsbac_acl_group_entry_t * entry_p;
           long desc_count;
    struct rsbac_acl_entry_desc_t           desc;

    rsbac_list_lol_remove(gm_handle, &user);
    /* traverse groups for this owner */
    desc_count = rsbac_list_get_all_data(group_handle, (void **) &entry_p);
    if(desc_count > 0)
      {
        for(i=0; i<desc_count; i++)
          {
            if(entry_p[i].owner == user)
              {
                rsbac_list_remove(group_handle, &entry_p[i].id);
                /* cleanup group memberships */
                rsbac_list_lol_subremove_from_all(gm_handle,
                                                  &entry_p[i].id);
              }
          }
        vfree(entry_p);
      }

    desc.subj_type = ACLS_USER;
    desc.subj_id = user;

    return rsbac_acl_remove_subject(desc);
  }

/* end of acl_data_structures.c */
