/************************************************* */
/* Rule Set Based Access Control                   */
/* Implementation of RSBAC general system calls    */
/* Author and (C) 1999,2000: Amon Ott              */
/*                                                 */
/* Last modified: 10/Nov/2000                      */
/************************************************* */

#include <rsbac/types.h>
#include <rsbac/aci.h>
#include <rsbac/pm.h>
#include <rsbac/auth.h>
#include <rsbac/acl.h>
#include <rsbac/error.h>
#include <rsbac/debug.h>
#include <rsbac/helpers.h>
#include <rsbac/getname.h>
#include <asm/segment.h>
#include <asm/semaphore.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>

#include <rsbac/adf.h>
#include <rsbac/adf_main.h>
#include <rsbac/adf_syshelpers.h>

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

extern struct semaphore rsbac_write_sem;

/************************************************* */
/*              Declarations                       */
/************************************************* */

/************************************************* */
/*              General functions                  */
/************************************************* */

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

asmlinkage int sys_rsbac_stats(void)
  {
    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_stats(): calling ADF\n");
    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;
      }

    if (rsbac_debug_aef)
      printk(KERN_DEBUG "sys_rsbac_stats(): getting RSBAC status!\n");
    return(rsbac_stats());
  };

asmlinkage int sys_rsbac_check(int correct, int check_inode)
  {
    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;
    int result;

    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_check(): calling ADF\n");
    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;
      }

/*    if (rsbac_debug_aef) */
#ifdef CONFIG_RSBAC_RMSG
    rsbac_printk(KERN_INFO
           "sys_rsbac_check(): triggering RSBAC consistency check, correct = %u, check_inode = %u!\n",
           correct, check_inode);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
    printk(KERN_INFO
           "sys_rsbac_check(): triggering RSBAC consistency check, correct = %u, check_inode = %u!\n",
           correct, check_inode);
#endif
    lock_kernel();
    /* rsbac write blocking */
    if(check_inode)
      down(&rsbac_write_sem);

    result = rsbac_check(correct, check_inode);
    /* call other checks */
    #if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    if(!result)
      result=rsbac_check_auth(correct, check_inode);
    #endif
    #if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
    if(!result)
      result=rsbac_check_acl(correct, check_inode);
    #endif
    /* release write blocking */
    if(check_inode)
      up(&rsbac_write_sem);

    unlock_kernel();
    return(result);
  };

asmlinkage int sys_rsbac_write(void)
  {
#if defined(CONFIG_RSBAC_AUTO_WRITE)
    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;
    int result;

    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_write(): calling ADF\n");
    rsbac_target_id.scd = ST_rsbac;
    rsbac_attribute_value.dummy = 0;
    if (!rsbac_adf_request(R_WRITE,
                           current->pid,
                           T_SCD,
                           rsbac_target_id,
                           A_none,
                           rsbac_attribute_value))
      {
        return -EPERM;
      }

    if (rsbac_debug_aef)
      printk(KERN_DEBUG "sys_rsbac_write(): saving RSBAC attributes!\n");
/*    lock_kernel(); -> rsbac_write(need_lock) */
    result = rsbac_write(TRUE);
/*    unlock_kernel(); */
    return result;
#else
    return(0);
#endif /* CONFIG_RSBAC_AUTO_WRITE */
  };

/************************************************* */
/*               Attribute functions               */
/************************************************* */

asmlinkage int sys_rsbac_get_attr(enum rsbac_target_t target,
                   union rsbac_target_id_t * tid,
                   enum rsbac_attribute_t attr,
                   union rsbac_attribute_value_t * value,
                   int inherit)
    { 
      union rsbac_target_id_t k_tid;
      union rsbac_attribute_value_t k_value;
      int   err = 0;
      boolean i_inherit;

      if(!tid || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
      if(!value)
        return(-RSBAC_EINVALIDVALUE);
      if(attr >= A_none)
        return(-RSBAC_EINVALIDATTR);
        
      /* get values from user space */
      rsbac_get_user((u_char *) &k_tid, (u_char *) tid, sizeof(k_tid) );
      rsbac_get_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );

      if(inherit)
        i_inherit = TRUE;
      else
        i_inherit = FALSE;

      if(   (target == T_IPC)
         && (k_tid.ipc.type == I_sockid)
        )
        {
          int fd = k_tid.ipc.id.id_nr & ((1 << 16) -1);
          int pid = k_tid.ipc.id.id_nr >> 16;
          struct sock * sock_p;
          struct task_struct * task_p;
          struct file * file_p;
          
          read_lock(&tasklist_lock);
          task_p = find_task_by_pid(pid);
          if(   !task_p
             || !task_p->files
             #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
             || !((file_p = fcheck_task(task_p, fd)))
             #else
             || !((file_p = fcheck_files(task_p->files, fd)))
             #endif
             || !file_p->f_dentry
             || !file_p->f_dentry->d_inode
             || !S_ISSOCK(file_p->f_dentry->d_inode->i_mode)
             || !((sock_p = file_p->f_dentry->d_inode->u.socket_i.sk))
            )
            {
              read_unlock(&tasklist_lock);
              return(-RSBAC_EINVALIDTARGET);
            }
          read_unlock(&tasklist_lock);
          k_tid.ipc.type = I_sock;
          k_tid.ipc.id.sock = sock_p;
        }
      
      /* call ADF */
      if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr(): calling ADF\n");
      if (!rsbac_adf_request(R_READ_ATTRIBUTE,
                             current->pid,
                             target,
                             k_tid,
                             attr,
                             k_value))
        {
          return -EPERM;
        }

      err = rsbac_get_attr(target, k_tid, attr, &k_value, i_inherit);
      /* put result value to user space */
      if(!err)
        {
          err = rsbac_put_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );
        }
      return (err);
    };      /* end of sys_rsbac_get_attr() */


asmlinkage int sys_rsbac_get_attr_n(enum rsbac_target_t target,
                   char * t_name,
                   enum rsbac_attribute_t attr,
                   union rsbac_attribute_value_t * value,
                   int inherit)
    { 
      union rsbac_attribute_value_t k_value;
      struct dentry * t_dentry;
      int     err = 0;
      union rsbac_target_id_t  tid;
/*    struct passwd * user_description_p; */
      boolean i_inherit;
      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif

      if(!t_name || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
      if(!value)
        return(-RSBAC_EINVALIDVALUE);
      if(attr >= A_none)
        return(-RSBAC_EINVALIDATTR);
        
      if(inherit)
        i_inherit = TRUE;
      else
        i_inherit = FALSE;

      /* get values from user space */
/*      if (rsbac_debug_aef)
        printk(KERN_DEBUG
               "sys_rsbac_get_attr_n(): getting values from user space\n"); */

      rsbac_get_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );
      
      switch (target)
        {
          case T_FILE:
            /* lookup filename */
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = PTR_ERR(t_dentry);
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): call to lookup_dentry() returned %i\n", err);
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): file not found\n");
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                && !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no file\n");
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* fill target id and call internal function */
            tid.file.device = t_dentry->d_inode->i_dev;
            tid.file.inode  = t_dentry->d_inode->i_ino;
            tid.file.dentry_p = t_dentry;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr_n(): calling ADF\n");
            if (!rsbac_adf_request(R_READ_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   attr,
                                   k_value))
              {
                err = -EPERM;
                goto out_dput;
              }
            err = rsbac_get_attr(target, tid, attr, &k_value, i_inherit);
/*            if (rsbac_debug_aef)
                printk(KERN_DEBUG "sys_rsbac_get_attr_n(): rsbac_get_attr() returned %i\n", err); */
            /* put result value to user space */
            if(!err)
              rsbac_put_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );
            goto out_dput;

          case T_DIR:
            /* lookup filename */
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = PTR_ERR(t_dentry);
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG
                         "sys_rsbac_get_attr(): call to lookup_dentry() returned %i\n",
                          err);
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): dir not found\n");
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type dir? */
            if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
              {
                if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr(): no dir\n");
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* fill target id and call internal function */
            tid.dir.device = t_dentry->d_inode->i_dev;
            tid.dir.inode  = t_dentry->d_inode->i_ino;
            tid.dir.dentry_p = t_dentry;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr_n(): calling ADF\n");
            if (!rsbac_adf_request(R_READ_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   attr,
                                   k_value))
              {
                err = -EPERM;
                goto out_dput;
              }
            err = rsbac_get_attr(target, tid, attr, &k_value, i_inherit);
/*            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr(): rsbac_get_attr() returned %i\n", err); */
            if(!err)
              rsbac_put_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );
            goto out_dput;

          case T_DEV:
            /* lookup filename */
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = PTR_ERR(t_dentry);
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG
                         "sys_rsbac_get_attr_n(): call to lookup_dentry() returned %i\n",
                         err);
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_get_attr_n(): dev file not found\n");
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type block/char device? */
            if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              {
                if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr_n(): no dev\n");
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* fill target id and call internal function */
            if(S_ISBLK(t_dentry->d_inode->i_mode))
              tid.dev.type = D_block;
            else
              tid.dev.type = D_char;
            tid.dev.id  = t_dentry->d_inode->i_rdev;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr_n(): calling ADF\n");
            if (!rsbac_adf_request(R_READ_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   attr,
                                   k_value))
              {
                err = -EPERM;
                goto out_dput;
              }
            /* get value from DS, but do not inherit */
            err = rsbac_get_attr(target, tid, attr, &k_value, FALSE);
/*            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_get_attr_n(): rsbac_get_attr() returned %i\n", err); */
            /* put result value to user space */
            if(!err)
              rsbac_put_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );
            goto out_dput;

          default:
            return -RSBAC_EINVALIDTARGET;
        }
out:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      unlock_kernel();
      #endif
      return(err);

out_dput:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      dput(t_dentry);
      #else
      path_release(&nd);
      #endif
      goto out;
    };      /* end of sys_rsbac_get_attr_n() */

/************************************************************************** */

asmlinkage int sys_rsbac_set_attr(enum rsbac_target_t target,
                   union rsbac_target_id_t * tid,
                   enum rsbac_attribute_t attr,
                   union rsbac_attribute_value_t * value)

    { 
      union rsbac_target_id_t k_tid;
      union rsbac_attribute_value_t k_value;
      int   err = 0;
      struct task_struct * task_p;
      
      if(!tid || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
      if(!value)
        return(-RSBAC_EINVALIDVALUE);
      if(attr >= A_none)
        return(-RSBAC_EINVALIDATTR);
        
      /* get values from user space */
      rsbac_get_user((u_char *) &k_tid, (u_char *) tid, sizeof(k_tid) );
      rsbac_get_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );

      switch(target)
        {
          case T_IPC:
            if(k_tid.ipc.type == I_sockid)
            {
              int fd = k_tid.ipc.id.id_nr & ((1 << 16) -1);
              int pid = k_tid.ipc.id.id_nr >> 16;
              struct sock * sock_p;
              struct file * file_p;
          
              read_lock(&tasklist_lock);
              task_p = find_task_by_pid(pid);
              if(   !task_p
                 || !task_p->files
                 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                 || !((file_p = fcheck_task(task_p, fd)))
                 #else
                 || !((file_p = fcheck_files(task_p->files, fd)))
                 #endif
                 || !file_p->f_dentry
                 || !file_p->f_dentry->d_inode
                 || !S_ISSOCK(file_p->f_dentry->d_inode->i_mode)
                 || !((sock_p = file_p->f_dentry->d_inode->u.socket_i.sk))
                )
                {
                  read_unlock(&tasklist_lock);
                  return(-RSBAC_EINVALIDTARGET);
                }
              read_unlock(&tasklist_lock);
              k_tid.ipc.type = I_sock;
              k_tid.ipc.id.sock = sock_p;
            }
            break;

          case T_PROCESS:
            read_lock(&tasklist_lock);
            task_p = find_task_by_pid(k_tid.process);
            read_unlock(&tasklist_lock);
            if(!task_p)
              return(-RSBAC_EINVALIDTARGET);

          default:
            break;
        }
      
      /* call ADF */
      if (rsbac_debug_aef)
        printk(KERN_DEBUG
               "sys_rsbac_set_attr(): calling ADF\n");
      if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                             current->pid,
                             target,
                             k_tid,
                             attr,
                             k_value))
        {
          return -EPERM;
        }
      err = rsbac_set_attr(target, k_tid, attr, k_value);
      return (err);
    };      /* end of sys_rsbac_set_attr() */

asmlinkage int sys_rsbac_set_attr_n(enum rsbac_target_t target,
                   char * t_name,
                   enum rsbac_attribute_t attr,
                   union rsbac_attribute_value_t * value)

    {
      struct dentry * t_dentry;
      int     err = 0;
      union rsbac_attribute_value_t k_value;
      union rsbac_target_id_t  tid;
      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif

      if(!t_name || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
      if(!value)
        return(-RSBAC_EINVALIDVALUE);
      if(attr >= A_none)
        return(-RSBAC_EINVALIDATTR);
        
      /* get values from user space */
      rsbac_get_user((u_char *) &k_value, (u_char *) value, sizeof(k_value) );
      
      switch (target)
        {
          case T_FILE:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err= -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_set_attr_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                && !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              { /* This is no file or device */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            tid.file.device = t_dentry->d_inode->i_dev;
            tid.file.inode  = t_dentry->d_inode->i_ino;
            tid.file.dentry_p = t_dentry;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_set_attr_n(): calling ADF\n");
            if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   attr,
                                   k_value))
              {
                err = -EPERM;
              }
            else
              {
                err = rsbac_set_attr(target, tid, attr, k_value);
              }
            goto out_dput;

          case T_DIR:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_set_attr_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
              { /* This is no dir */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
            tid.dir.inode  = t_dentry->d_inode->i_ino;
            tid.dir.dentry_p = t_dentry;
            /* call ADF */
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "sys_rsbac_set_attr_n(): calling ADF\n");
            if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   attr,
                                   k_value))
              {
                err = -EPERM;
              }
            else
              {
                err = rsbac_set_attr(target, tid, attr, k_value);
              }
            goto out_dput;

          case T_DEV:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_set_attr_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              { /* This is no file or device */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* fill target id and call internal function */
            if(S_ISBLK(t_dentry->d_inode->i_mode))
              tid.dev.type = D_block;
            else
              tid.dev.type = D_char;
            tid.dev.id  = t_dentry->d_inode->i_rdev;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_set_attr_n(): calling ADF\n");
            if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   attr,
                                   k_value))
              {
                err = -EPERM;
              }
            else
              {
                err = rsbac_set_attr(target, tid, attr, k_value);
              }
            goto out_dput;

          default:
            return -RSBAC_EINVALIDTARGET;
        }

out:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      unlock_kernel();
      #endif
      return(err);

out_dput:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      dput(t_dentry);
      #else
      path_release(&nd);
      #endif
      goto out;
    };      /* end of sys_rsbac_set_attr_n() */

/************************************************************************** */

asmlinkage int sys_rsbac_remove_target(enum rsbac_target_t target,
                        union rsbac_target_id_t * tid)
    { 
      union rsbac_target_id_t k_tid;
      int   err = 0;

      /* for adf_request */
      union rsbac_attribute_value_t rsbac_attribute_value;
      
      if(!tid || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
        
      /* get values from user space */
      rsbac_get_user((u_char *) &k_tid, (u_char *) tid, sizeof(k_tid) );

      if(   (target == T_IPC)
         && (k_tid.ipc.type == I_sockid)
        )
        {
          int fd = k_tid.ipc.id.id_nr & ((1 << 16) -1);
          int pid = k_tid.ipc.id.id_nr >> 16;
          struct sock * sock_p;
          struct task_struct * task_p;
          struct file * file_p;
          
          read_lock(&tasklist_lock);
          task_p = find_task_by_pid(pid);
          if(   !task_p
             || !task_p->files
             #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
             || !((file_p = fcheck_task(task_p, fd)))
             #else
             || !((file_p = fcheck_files(task_p->files, fd)))
             #endif
             || !file_p->f_dentry
             || !file_p->f_dentry->d_inode
             || !S_ISSOCK(file_p->f_dentry->d_inode->i_mode)
             || !((sock_p = file_p->f_dentry->d_inode->u.socket_i.sk))
            )
            {
              read_unlock(&tasklist_lock);
              return(-RSBAC_EINVALIDTARGET);
            }
          read_unlock(&tasklist_lock);
          k_tid.ipc.type = I_sock;
          k_tid.ipc.id.sock = sock_p;
        }
      
      /* call ADF */
      if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_remove_target(): calling ADF\n");
      rsbac_attribute_value.dummy = 0;
      if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                             current->pid,
                             target,
                             k_tid,
                             A_none,
                             rsbac_attribute_value))
        {
          return -EPERM;
        }
      err = rsbac_remove_target(target, k_tid);
      return (err);
    };      /* end of sys_rsbac_remove_target() */

asmlinkage int sys_rsbac_remove_target_n(enum rsbac_target_t target,
                            char * t_name)
    { 
      struct dentry * t_dentry;
      int     err = 0;
      union rsbac_target_id_t  tid;

      /* for adf_request */
      union rsbac_attribute_value_t rsbac_attribute_value;

/*    struct passwd * user_description_p; */
      
      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif

      if(!t_name || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
        
      switch (target)
        {
          case T_FILE:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_remove_target_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                && !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              { /* This is no file or device */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            tid.file.device = t_dentry->d_inode->i_sb->s_dev;
            tid.file.inode  = t_dentry->d_inode->i_ino;
            tid.file.dentry_p = t_dentry;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_remove_target_n(): calling ADF\n");
            rsbac_attribute_value.dummy = 0;
            if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   A_none,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
              }
            else
              {
                err = rsbac_remove_target(target, tid);
              }
            goto out_dput;

          case T_DIR:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_remove_target_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
              { /* This is no file */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
            tid.dir.inode  = t_dentry->d_inode->i_ino;
            tid.dir.dentry_p = t_dentry;
            /* call ADF */
            if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_remove_target_n(): calling ADF\n");
            rsbac_attribute_value.dummy = 0;
            if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   A_none,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
              }
            else
              {
                err = rsbac_remove_target(target, tid);
              }
            goto out_dput;

          case T_DEV:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef)
                  printk(KERN_DEBUG "sys_rsbac_remove_target_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              { /* This is no dev */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* fill target id and call internal function */
            if(S_ISBLK(t_dentry->d_inode->i_mode))
              tid.dev.type = D_block;
            else
              tid.dev.type = D_char;
            tid.dev.id  = t_dentry->d_inode->i_rdev;
            /* call ADF */
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "sys_rsbac_remove_target_n(): calling ADF\n");
            rsbac_attribute_value.dummy = 0;
            if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                                   current->pid,
                                   target,
                                   tid,
                                   A_none,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
              }
            else
              {
                err = rsbac_remove_target(target, tid);
              }
            goto out_dput;

          default:
            return -RSBAC_EINVALIDTARGET;
        }
out:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      unlock_kernel();
      #endif
      return(err);

out_dput:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      dput(t_dentry);
      #else
      path_release(&nd);
      #endif
      goto out;
    };      /* end of sys_rsbac_remove_target_n() */


/************************************************* */
/*                 ADF functions                   */
/************************************************* */

asmlinkage int sys_rsbac_switch(enum rsbac_switch_target_t target, int value)
  {
#ifdef CONFIG_RSBAC_SWITCH
    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;
    char                         * switch_name;
  
    /* call ADF */
    if(target >= SW_NONE)
      return(-RSBAC_EINVALIDTARGET);
    if ((value != 0) && (value != 1))
      return (-RSBAC_EINVALIDVALUE);
    if (rsbac_debug_aef)
      printk(KERN_DEBUG "sys_rsbac_switch(): calling ADF\n");
    rsbac_target_id.dummy = 0;
    rsbac_attribute_value.switch_target = target;
    if (!rsbac_adf_request(R_SWITCH_MODULE,
                           current->pid,
                           T_NONE,
                           rsbac_target_id,
                           A_switch_target,
                           rsbac_attribute_value))
             {
               return -EPERM;
             }

    switch_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
    if(switch_name)
      {
        get_switch_target_name(switch_name,target);
#ifdef CONFIG_RSBAC_RMSG
        rsbac_printk(KERN_WARNING
               "sys_rsbac_switch(): switching RSBAC module %s (No. %i) to %i!\n",
               switch_name, target, value);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
        printk(KERN_WARNING
               "sys_rsbac_switch(): switching RSBAC module %s (No. %i) to %i!\n",
               switch_name, target, value);
#endif
        kfree(switch_name);
      }

    switch (target)
      {
#ifdef CONFIG_RSBAC_MAC
        case MAC: rsbac_switch_mac = value;
                  break;
#endif
#ifdef CONFIG_RSBAC_FC
        case FC:  rsbac_switch_fc = value;
                  break;
#endif
#ifdef CONFIG_RSBAC_SIM
        case SIM: rsbac_switch_sim = value;
                  break;
#endif
#ifdef CONFIG_RSBAC_PM
        case PM:  rsbac_switch_pm = value;
                  break;
#endif
#ifdef CONFIG_RSBAC_MS
        case MS:  rsbac_switch_ms = value;
                  break;
#endif
#ifdef CONFIG_RSBAC_FF
        case FF:  rsbac_switch_ff = value;
                  break;
#endif
#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
        case RC:  rsbac_switch_rc = value;
                  break;
#endif
#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
        case AUTH: rsbac_switch_auth = value;
                  break;
#endif
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
        case ACL: rsbac_switch_acl = value;
                  break;
#endif
        default:  return(-RSBAC_EINVALIDTARGET);
      }
#endif
    return(0); 
  };

/************** MAC ***************/

asmlinkage int sys_rsbac_mac_set_curr_seclevel(rsbac_security_level_t level)
  {
#ifdef CONFIG_RSBAC_MAC
    if(level > SL_max)
      return(-RSBAC_EINVALIDVALUE);
    return (rsbac_mac_set_curr_seclevel(level));
#else
    return(-RSBAC_EINVALIDREQUEST); 
#endif
  };

asmlinkage rsbac_security_level_t sys_rsbac_mac_get_curr_seclevel(void)
  {
#ifdef CONFIG_RSBAC_MAC
    return (rsbac_mac_get_curr_seclevel());
#else
    return(SL_unclassified); 
#endif
  };

asmlinkage int sys_rsbac_mac_set_max_seclevel(rsbac_security_level_t level)
  {
#ifdef CONFIG_RSBAC_MAC
    if(level > SL_max)
      return(-RSBAC_EINVALIDVALUE);
    return (rsbac_mac_set_max_seclevel(level));
#else
    return(-RSBAC_EINVALIDREQUEST); 
#endif
  };

asmlinkage rsbac_security_level_t sys_rsbac_mac_get_max_seclevel(void)
  {
#ifdef CONFIG_RSBAC_MAC
    return (rsbac_mac_get_max_seclevel());
#else
    return(SL_unclassified); 
#endif
  };

asmlinkage int sys_rsbac_mac_set_curr_categories(rsbac_mac_category_vector_t * categories_p)
  {
#ifdef CONFIG_RSBAC_MAC
    rsbac_mac_category_vector_t k_categories;
    int err;

    err = rsbac_get_user((u_char *) &k_categories, (u_char *) categories_p, sizeof(k_categories) );
    if(err)
      return err;
    else
      return (rsbac_mac_set_curr_categories(k_categories));
#else
    return(-RSBAC_EINVALIDREQUEST); 
#endif
  };

asmlinkage int sys_rsbac_mac_get_curr_categories(rsbac_mac_category_vector_t * categories_p)
  {
#ifdef CONFIG_RSBAC_MAC
    int err;
    rsbac_mac_category_vector_t k_categories;

    err = rsbac_mac_get_curr_categories(&k_categories);
    /* put result value to user space */
    if(!err)
      {
        err = rsbac_put_user((u_char *) &k_categories,
                             (u_char *) categories_p,
                             sizeof(k_categories) );
      }
    return (err);
#else
    return(-RSBAC_EINVALIDREQUEST); 
#endif
  };

asmlinkage int sys_rsbac_mac_set_max_categories(rsbac_mac_category_vector_t * categories_p)
  {
#ifdef CONFIG_RSBAC_MAC
    rsbac_mac_category_vector_t k_categories;
    int err;

    err = rsbac_get_user((u_char *) &k_categories, (u_char *) categories_p, sizeof(k_categories) );
    if(err)
      return err;
    else
      return (rsbac_mac_set_max_categories(k_categories));
#else
    return(-RSBAC_EINVALIDREQUEST); 
#endif
  };

asmlinkage int sys_rsbac_mac_get_max_categories(rsbac_mac_category_vector_t * categories_p)
  {
#ifdef CONFIG_RSBAC_MAC
    int err;
    rsbac_mac_category_vector_t k_categories;

    err = rsbac_mac_get_max_categories(&k_categories);
    /* put result value to user space */
    if(!err)
      {
        err = rsbac_put_user((u_char *) &k_categories,
                             (u_char *) categories_p,
                             sizeof(k_categories) );
      }
    return (err);
#else
    return(-RSBAC_EINVALIDREQUEST); 
#endif
  };

/************** PM ***************/

asmlinkage int sys_rsbac_stats_pm(void)
  {
#ifndef CONFIG_RSBAC_PM
    return (0);
#else
    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_stats_pm(): calling ADF\n");
    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;
      }

    if (rsbac_debug_aef_pm)
      printk(KERN_DEBUG "sys_rsbac_stats_pm(): getting RSBAC status!\n");
    return(rsbac_stats_pm());
#endif
  };

asmlinkage int sys_rsbac_pm(enum  rsbac_pm_function_type_t    function,
                            union rsbac_pm_function_param_t * param_p,
                                  rsbac_pm_tkt_id_t           ticket)
  {
#ifndef CONFIG_RSBAC_PM
    return (-RSBAC_EINVALIDREQUEST);
#else
    union  rsbac_pm_function_param_t k_param;
    int result;
    
    if(function >= PF_none)
      return(-RSBAC_EINVALIDREQUEST);
    if(!param_p)
      return(-RSBAC_EINVALIDPOINTER);
    if (rsbac_debug_aef_pm)
      printk(KERN_DEBUG "sys_rsbac_pm(): called for function %i!\n",
             function);
    /* get parameters from user space */
    rsbac_get_user((u_char *) &k_param, (u_char *) param_p, sizeof(k_param) );
    /* call pm function and return its result */
    lock_kernel();
    result = rsbac_pm(function, k_param, ticket);
    unlock_kernel();
    return result;
#endif    
  }

asmlinkage int sys_rsbac_pm_change_current_task(rsbac_pm_task_id_t task)
  {
#ifndef CONFIG_RSBAC_PM
    return (0);
#else
    if (rsbac_debug_aef_pm)
      printk(KERN_DEBUG
             "sys_rsbac_pm_change_current_task(): called for task %i!\n",
             task);
    /* call pm function and return its result */
    return(rsbac_pm_change_current_task(task));
#endif    
  }

asmlinkage int sys_rsbac_pm_create_file(const char * filename,
                                        int mode,
                                        rsbac_pm_object_class_id_t class)
  {
#ifndef CONFIG_RSBAC_PM
    return (-RSBAC_EINVALIDREQUEST);
#else
    if(!filename)
      return(-RSBAC_EINVALIDPOINTER);
    if (rsbac_debug_aef_pm)
      printk(KERN_DEBUG
             "sys_rsbac_pm_create_file(): called with class %i!\n",
             class);
    /* call pm function and return its result */
    return(rsbac_pm_create_file(filename, mode, class));
#endif    
  }

/************** MS ***************/

asmlinkage int sys_rsbac_ms_get_copied(int fd)
  {
#ifndef CONFIG_RSBAC_MS
    return (-RSBAC_EINVALIDREQUEST);
#else
    union rsbac_target_id_t       i_tid;
    union rsbac_attribute_value_t i_attr_val1;
    struct sock * sock_p;
    struct file * file_p;

    if(   !current->files
       || !((file_p = fcheck(fd)))
       || !file_p->f_dentry
       || !file_p->f_dentry->d_inode
       || !S_ISSOCK(file_p->f_dentry->d_inode->i_mode)
       || !((sock_p = file_p->f_dentry->d_inode->u.socket_i.sk))
      )
      return(-RSBAC_EINVALIDTARGET);

    /* get ms_scanned for sock */
    i_tid.ipc.type = I_sock;
    i_tid.ipc.id.sock = sock_p;
    if (rsbac_get_attr(T_IPC,
                       i_tid,
                       A_ms_scanned,
                       &i_attr_val1,
                       FALSE))
      {
        printk(KERN_WARNING
               "sys_rsbac_ms_get_copied(): rsbac_get_attr() returned error!\n");
        return (-RSBAC_EREADFAILED);
      }
    /* only return value, if previously active rejected */
    if(i_attr_val1.ms_scanned != MS_active_rejected)
      return (-RSBAC_EINVALIDTARGET);

    /* OK, process may get copied value -> get it */
    if (rsbac_get_attr(T_IPC,
                       i_tid,
                       A_ms_buflen,
                       &i_attr_val1,
                       FALSE))
      {
        printk(KERN_WARNING
               "sys_rsbac_ms_get_copied(): rsbac_get_attr() returned error!\n");
        return (-RSBAC_EREADFAILED);
      }
    return(i_attr_val1.ms_buflen);
#endif
  };

/************** RC ***************/

/* All roles are always there, so instead of creation, we supply a copy for */
/* initialization. There is always the well-defined role general to copy    */
asmlinkage int sys_rsbac_rc_copy_role (rsbac_rc_role_id_t from_role,
                                       rsbac_rc_role_id_t to_role)
  {
#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
    if(   (from_role > RSBAC_RC_MAX_ROLE)
       || (from_role > RSBAC_RC_MAX_ROLE))
      return(-RSBAC_EINVALIDVALUE);
    if (rsbac_debug_aef_rc)
      printk(KERN_DEBUG
             "sys_rsbac_rc_copy_role(): from %i, to %i!\n",
             from_role, to_role);
    /* call rc function and return its result */
    return(rsbac_rc_sys_copy_role(from_role, to_role));
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/* Getting values */
asmlinkage int sys_rsbac_rc_get_item (enum  rsbac_rc_target_t       target,
                                      union rsbac_rc_target_id_t  * tid_p,
                                      enum  rsbac_rc_item_t         item,
                                      union rsbac_rc_item_value_t * value_p)
  {
#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
    union rsbac_rc_target_id_t  k_tid;
    union rsbac_rc_item_value_t k_value;
    int err = 0;

    if(   (target >= RT_NONE)
       || (item >= RI_none))
      return(-RSBAC_EINVALIDVALUE);
    /* get values from user space */
    rsbac_get_user((u_char *) &k_tid, (u_char *) tid_p, sizeof(k_tid) );
    rsbac_get_user((u_char *) &k_value, (u_char *) value_p, sizeof(k_value) );
    if (rsbac_debug_aef_rc)
      printk(KERN_DEBUG
             "sys_rsbac_rc_get_item(): target %i, item %i!\n",
             target, item);
    /* call rc function and return its result */
    err = rsbac_rc_sys_get_item(target, k_tid, item, &k_value);
    /* put result value to user space */
    if(!err)
      {
        err = rsbac_put_user((u_char *) &k_value, (u_char *) value_p, sizeof(k_value) );
      }
    return (err);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/* Setting values */
asmlinkage int sys_rsbac_rc_set_item (enum  rsbac_rc_target_t       target,
                                      union rsbac_rc_target_id_t    * tid_p,
                                      enum  rsbac_rc_item_t         item,
                                      union rsbac_rc_item_value_t   * value_p)
  {
#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
    union rsbac_rc_target_id_t  k_tid;
    union rsbac_rc_item_value_t k_value;

    if(   (target >= RT_NONE)
       || (item >= RI_none))
      return(-RSBAC_EINVALIDVALUE);
    /* get values from user space */
    rsbac_get_user((u_char *) &k_tid, (u_char *) tid_p, sizeof(k_tid) );
    rsbac_get_user((u_char *) &k_value, (u_char *) value_p, sizeof(k_value) );
    if (rsbac_debug_aef_rc)
      printk(KERN_DEBUG
             "sys_rsbac_rc_set_item(): target %i, item %i!\n",
             target, item);
    /* call rc function and return its result */
    return rsbac_rc_sys_set_item(target, k_tid, item, k_value);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/* Set own role */
asmlinkage int sys_rsbac_rc_change_role (rsbac_rc_role_id_t role)
  {
#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
    if(role > RSBAC_RC_MAX_ROLE)
      return(-RSBAC_EINVALIDVALUE);
    if (rsbac_debug_aef_rc)
      printk(KERN_DEBUG
             "sys_rsbac_rc_change_role(): role %i!\n",
             role);
    /* call rc function and return its result */
    return rsbac_rc_sys_change_role(role);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/* Getting own effective rights */
asmlinkage int sys_rsbac_rc_get_eff_rights_n(enum  rsbac_target_t   target,
                                                   char           * t_name,
                                                   rsbac_rc_request_vector_t * request_vector_p)
  {
#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
      struct dentry * t_dentry;
      int     err = 0;
      rsbac_rc_request_vector_t k_req_vec;
      union rsbac_target_id_t  tid;

      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif

      if(!t_name || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
        
      switch (target)
        {
          case T_FILE:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef_rc)
                  printk(KERN_DEBUG "sys_rsbac_rc_get_eff_rights_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                && !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              { /* This is no file or device */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            tid.file.device = t_dentry->d_inode->i_sb->s_dev;
            tid.file.inode  = t_dentry->d_inode->i_ino;
            tid.file.dentry_p = t_dentry;
            err = rsbac_rc_sys_get_eff_rights(T_FILE, tid, &k_req_vec);
            /* put result value to user space */
            if(!err)
              {
                err = rsbac_put_user((u_char *) &k_req_vec, (u_char *) request_vector_p, sizeof(k_req_vec) );
              }
            goto out_dput;

          case T_DIR:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef_rc)
                  printk(KERN_DEBUG "sys_rsbac_rc_get_eff_rights_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
              { /* This is no file */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
            tid.dir.inode  = t_dentry->d_inode->i_ino;
            tid.dir.dentry_p = t_dentry;
            err = rsbac_rc_sys_get_eff_rights(T_DIR, tid, &k_req_vec);
            /* put result value to user space */
            if(!err)
              {
                err = rsbac_put_user((u_char *) &k_req_vec, (u_char *) request_vector_p, sizeof(k_req_vec) );
              }
            goto out_dput;

          case T_DEV:
            #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
            lock_kernel();
            t_dentry = lookup_dentry(t_name,NULL,0);
            if (IS_ERR(t_dentry))
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out;
              }
            #else
            if ((err = user_path_walk_link(t_name, &nd)))
              {
                if (rsbac_debug_aef_rc)
                  printk(KERN_DEBUG "sys_rsbac_rc_get_eff_rights_n(): call to user_path_walk_link() returned %i\n", err);
                goto out;
              }
            t_dentry = nd.dentry;
            #endif
            if (!t_dentry->d_inode)
              {
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* is inode of type file or block/char device? */
            if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
              { /* This is no dev */
                err = -RSBAC_EINVALIDTARGET;
                goto out_dput;
              }
            /* fill target id and call internal function */
            if(S_ISBLK(t_dentry->d_inode->i_mode))
              tid.dev.type = D_block;
            else
              tid.dev.type = D_char;
            tid.dev.id  = t_dentry->d_inode->i_rdev;
            err = rsbac_rc_sys_get_eff_rights(T_DEV, tid, &k_req_vec);
            /* put result value to user space */
            if(!err)
              {
                err = rsbac_put_user((u_char *) &k_req_vec, (u_char *) request_vector_p, sizeof(k_req_vec) );
              }
            goto out_dput;

          default:
            return -RSBAC_EINVALIDTARGET;
        }
  out:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      unlock_kernel();
      #endif
      return(err);

  out_dput:
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
      dput(t_dentry);
      #else
      path_release(&nd);
      #endif
      goto out;
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/************** AUTH ***************/

/* Provide means for adding and removing of capabilities */
asmlinkage int sys_rsbac_auth_add_p_cap(rsbac_pid_t pid,
                                        rsbac_uid_t first_uid,
                                        rsbac_uid_t last_uid)
  {
#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    struct task_struct * task_p;

    read_lock(&tasklist_lock);
    task_p = find_task_by_pid(pid);
    read_unlock(&tasklist_lock);
    if(!task_p)
      return(-RSBAC_EINVALIDTARGET);
    if(first_uid > last_uid)
      return(-RSBAC_EINVALIDVALUE);

    /* call auth function and return its result */
    /* permission checking is done there */
    return(rsbac_auth_add_p_cap(pid, first_uid, last_uid));
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

asmlinkage int sys_rsbac_auth_remove_p_cap(rsbac_pid_t pid,
                                           rsbac_uid_t first_uid,
                                           rsbac_uid_t last_uid)
  {
#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    struct task_struct * task_p;

    if(first_uid > last_uid)
      return(-RSBAC_EINVALIDVALUE);

    read_lock(&tasklist_lock);
    task_p = find_task_by_pid(pid);
    read_unlock(&tasklist_lock);
    if(!task_p)
      return(-RSBAC_EINVALIDTARGET);
    /* call auth function and return its result */
    /* permission checking is done there */
    return(rsbac_auth_remove_p_cap(pid, first_uid, last_uid));
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

asmlinkage int sys_rsbac_auth_add_f_cap(char * filename,
                                        rsbac_uid_t first_uid,
                                        rsbac_uid_t last_uid)
  {
#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    struct dentry * t_dentry;
    int     err = 0;
    union rsbac_target_id_t  tid;

    /* for adf_request */
#if defined(CONFIG_RSBAC_AUTH)
    union rsbac_attribute_value_t rsbac_attribute_value;
#endif

    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
    struct nameidata nd;
    #endif

    if(!filename)
      return(-RSBAC_EINVALIDTARGET);
    if(first_uid > last_uid)
      return(-RSBAC_EINVALIDVALUE);

    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    lock_kernel();
    t_dentry = lookup_dentry(filename,NULL,0);
    if (IS_ERR(t_dentry))
      {
        err = -RSBAC_EINVALIDTARGET;
        goto out;
      }
    #else
    if ((err = user_path_walk_link(filename, &nd)))
      {
        if (rsbac_debug_aef_auth)
          printk(KERN_DEBUG "sys_rsbac_auth_add_f_cap(): call to user_path_walk_link() returned %i\n", err);
        goto out;
      }
    t_dentry = nd.dentry;
    #endif
    if (!t_dentry->d_inode)
      {
        err = -RSBAC_EINVALIDTARGET;
        goto out_dput;
      }
    /* is inode of type file? */
    if (!S_ISREG(t_dentry->d_inode->i_mode))
      { /* This is no file */
        err = -RSBAC_EINVALIDTARGET;
        goto out_dput;
      }
    tid.file.device = t_dentry->d_inode->i_sb->s_dev;
    tid.file.inode  = t_dentry->d_inode->i_ino;
    tid.file.dentry_p = t_dentry;
#if defined(CONFIG_RSBAC_AUTH)
    /* call ADF */
    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_auth_add_f_cap(): calling ADF\n");
    rsbac_attribute_value.auth_cap = first_uid;
    if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                           current->pid,
                           T_FILE,
                           tid,
                           A_auth_add_f_cap,
                           rsbac_attribute_value))
      {
        err = -EPERM;
      }
    else
#endif
      err = rsbac_auth_add_f_cap(tid.file, first_uid, last_uid);

out_dput:
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    dput(t_dentry);
    #else
    path_release(&nd);
    #endif
out:
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    unlock_kernel();
    #endif
    return(err);

#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

asmlinkage int sys_rsbac_auth_remove_f_cap(char * filename,
                                           rsbac_uid_t first_uid,
                                           rsbac_uid_t last_uid)
  {
#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    struct dentry * t_dentry;
    int     err = 0;
    union rsbac_target_id_t  tid;

    /* for adf_request */
#if defined(CONFIG_RSBAC_AUTH)
    union rsbac_attribute_value_t rsbac_attribute_value;
#endif

    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
    struct nameidata nd;
    #endif

    if(!filename)
      return(-RSBAC_EINVALIDTARGET);
    if(first_uid > last_uid)
      return(-RSBAC_EINVALIDVALUE);

    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    lock_kernel();
    t_dentry = lookup_dentry(filename,NULL,0);
    if (IS_ERR(t_dentry))
      {
        err = -RSBAC_EINVALIDTARGET;
        goto out;
      }
    #else
    if ((err = user_path_walk_link(filename, &nd)))
      {
        if (rsbac_debug_aef_auth)
          printk(KERN_DEBUG "sys_rsbac_auth_remove_f_cap(): call to user_path_walk_link() returned %i\n", err);
        goto out;
      }
    t_dentry = nd.dentry;
    #endif
    if (!t_dentry->d_inode)
      {
        err = -RSBAC_EINVALIDTARGET;
        goto out_dput;
      }
    /* is inode of type file? */
    if (!S_ISREG(t_dentry->d_inode->i_mode))
      { /* This is no file */
        err = -RSBAC_EINVALIDTARGET;
        goto out_dput;
      }
    tid.file.device = t_dentry->d_inode->i_sb->s_dev;
    tid.file.inode  = t_dentry->d_inode->i_ino;
    tid.file.dentry_p = t_dentry;
#if defined(CONFIG_RSBAC_AUTH)
    /* call ADF */
    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_auth_add_f_cap(): calling ADF\n");
    rsbac_attribute_value.auth_cap = first_uid;
    if (!rsbac_adf_request(R_MODIFY_ATTRIBUTE,
                           current->pid,
                           T_FILE,
                           tid,
                           A_auth_remove_f_cap,
                           rsbac_attribute_value))
      {
        err = -EPERM;
      }
    else
#endif
      err = rsbac_auth_remove_f_cap(tid.file, first_uid, last_uid);

out_dput:
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    dput(t_dentry);
    #else
    path_release(&nd);
    #endif
out:
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    unlock_kernel();
    #endif
    return(err);

#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/* caplist must have space for 2 * maxnum uid entries - first and last each! */
asmlinkage int sys_rsbac_auth_get_f_caplist(char * filename,
                                            rsbac_uid_t caplist[],
                                            int maxnum)
  {
#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    struct dentry * t_dentry;
    int     err = 0, tmperr = 0;
    union rsbac_target_id_t  tid;
    rsbac_uid_t k_caplist[maxnum];

    /* for adf_request */
#if defined(CONFIG_RSBAC_AUTH)
    union rsbac_attribute_value_t rsbac_attribute_value;
#endif

    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
    struct nameidata nd;
    #endif

    if(!filename)
      return(-RSBAC_EINVALIDTARGET);
    if(!caplist)
      return(-RSBAC_EINVALIDPOINTER);
    if(maxnum <= 0)
      return(-RSBAC_EINVALIDVALUE);

    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    lock_kernel();
    t_dentry = lookup_dentry(filename,NULL,0);
    if (IS_ERR(t_dentry))
      {
        err = -RSBAC_EINVALIDTARGET;
        goto out;
      }
    #else
    if ((err = user_path_walk_link(filename, &nd)))
      {
        if (rsbac_debug_aef_auth)
          printk(KERN_DEBUG "sys_rsbac_auth_get_f_caplist(): call to user_path_walk_link() returned %i\n", err);
        goto out;
      }
    t_dentry = nd.dentry;
    #endif
    if (!t_dentry->d_inode)
      {
        err = -RSBAC_EINVALIDTARGET;
        goto out_dput;
      }
    /* is inode of type file? */
    if (!S_ISREG(t_dentry->d_inode->i_mode))
      { /* This is no file */
        err = -RSBAC_EINVALIDTARGET;
        goto out_dput;
      }
    tid.file.device = t_dentry->d_inode->i_sb->s_dev;
    tid.file.inode  = t_dentry->d_inode->i_ino;
    tid.file.dentry_p = t_dentry;
#if defined(CONFIG_RSBAC_AUTH)
    /* call ADF */
    if (rsbac_debug_aef) printk(KERN_DEBUG "sys_rsbac_auth_get_f_caplist(): calling ADF\n");
    rsbac_attribute_value.dummy = 0;
    if (!rsbac_adf_request(R_READ_ATTRIBUTE,
                           current->pid,
                           T_FILE,
                           tid,
                           A_auth_get_caplist,
                           rsbac_attribute_value))
      {
        err = -EPERM;
        goto out_dput;
      }
#endif
    err = rsbac_auth_get_f_caplist(tid.file, k_caplist, maxnum);
    if(err>0)
      {
        tmperr = rsbac_put_user((u_char *) &k_caplist, (u_char *) caplist,
                                sizeof(rsbac_uid_t) * 2 * err);
        if(tmperr < 0)
          err = tmperr;
      }

out_dput:
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    dput(t_dentry);
    #else
    path_release(&nd);
    #endif
out:
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
    unlock_kernel();
    #endif
    return(err);

#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
  };

/**********************************/
/************** ACL ***************/

asmlinkage int sys_rsbac_acl(enum   rsbac_acl_syscall_type_t call,
                             struct rsbac_acl_syscall_arg_t * arg)
    { 
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      struct rsbac_acl_syscall_arg_t k_arg;
/*      union rsbac_target_id_t i_tid; */
      int   err = 0;
      
      if(call >= ACLC_none)
        return(-RSBAC_EINVALIDREQUEST);
      if(!arg)
        return(-RSBAC_EINVALIDPOINTER);

      /* get values from user space */
      err = rsbac_get_user((u_char *) &k_arg, (u_char *) arg, sizeof(k_arg) );
      if(err < 0)
        return err;

      if(k_arg.target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
/*      printk(KERN_DEBUG "sys_rsbac_acl(): target = %u, call = %u, subj_type = %u, subj_id = %u!\n",
             k_arg.target, call, k_arg.subj_type, k_arg.subj_id); */
      if(call != ACLC_set_mask)
        {
          switch(k_arg.subj_type)
            {
              case ACLS_USER:
                break;
              case ACLS_GROUP:
                if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE)
                  {
                    struct rsbac_acl_group_entry_t entry;
                           rsbac_uid_t caller;

                    if(   rsbac_acl_get_group_entry(k_arg.subj_id, &entry)
                       || rsbac_get_owner(&caller)
                       || (   (entry.owner != caller)
                           && (entry.type != ACLG_GLOBAL)
                          )
                      )
                      return(-RSBAC_EINVALIDVALUE);
                  }
                break;
              #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
              case ACLS_ROLE:
                if(k_arg.subj_id > RSBAC_RC_MAX_ROLE)
                  {
                    printk(KERN_DEBUG "sys_rsbac_acl(): Invalid role %u!\n", k_arg.subj_id);
                    return(-RSBAC_EINVALIDVALUE);
                  }
                break;
              #endif
              default:
                printk(KERN_DEBUG "sys_rsbac_acl(): Invalid subject type %u!\n", k_arg.subj_type);
                return(-RSBAC_EINVALIDVALUE);
            }
          if(   (call == ACLC_remove_user)
             && (k_arg.target != T_USER)
            )
            return -RSBAC_EINVALIDTARGET;
          
        }
        
      /* call acl function */
      switch(call)
        {
          case ACLC_set_acl_entry:
            err = rsbac_acl_sys_set_acl_entry(k_arg.target,
                                              k_arg.tid,
                                              k_arg.subj_type,
                                              k_arg.subj_id,
                                              k_arg.rights);
            break;
          case ACLC_remove_acl_entry:
            err = rsbac_acl_sys_remove_acl_entry(k_arg.target,
                                                 k_arg.tid,
                                                 k_arg.subj_type,
                                                 k_arg.subj_id);
            break;
          case ACLC_remove_acl:
            err = rsbac_acl_sys_remove_acl(k_arg.target,
                                           k_arg.tid);
            break;
          case ACLC_add_to_acl_entry:
            err = rsbac_acl_sys_add_to_acl_entry(k_arg.target,
                                                 k_arg.tid,
                                                 k_arg.subj_type,
                                                 k_arg.subj_id,
                                                 k_arg.rights);
            break;
          case ACLC_remove_from_acl_entry:
            err = rsbac_acl_sys_remove_from_acl_entry(k_arg.target,
                                                      k_arg.tid,
                                                      k_arg.subj_type,
                                                      k_arg.subj_id,
                                                      k_arg.rights);
            break;
          case ACLC_set_mask:
            err = rsbac_acl_sys_set_mask(k_arg.target,
                                         k_arg.tid,
                                         k_arg.rights);
            break;
          case ACLC_remove_user:
            err = rsbac_acl_sys_remove_user(k_arg.tid.user);
            break;

          default:
            err=-RSBAC_EINVALIDREQUEST;
        }
      return (err);
#else
      return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl() */


asmlinkage int sys_rsbac_acl_n(enum   rsbac_acl_syscall_type_t call,
                               struct rsbac_acl_syscall_n_arg_t * arg)
    {
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      struct dentry * t_dentry = NULL;
      int     err = 0;
      boolean need_put = FALSE;
      union rsbac_target_id_t  tid;
      struct rsbac_acl_syscall_n_arg_t k_arg;

      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif

      if(call >= ACLC_none)
        return(-RSBAC_EINVALIDREQUEST);
      if(!arg)
        return(-RSBAC_EINVALIDPOINTER);

      /* get values from user space */
      err = rsbac_get_user((u_char *) &k_arg, (u_char *) arg, sizeof(k_arg) );
      if(err < 0)
        return err;

      if(k_arg.target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
      if(call != ACLC_set_mask)
        {
          switch(k_arg.subj_type)
            {
              case ACLS_USER:
                break;
              case ACLS_GROUP:
                if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE)
                  {
                    struct rsbac_acl_group_entry_t entry;
                           rsbac_uid_t caller;

                    if(   rsbac_acl_get_group_entry(k_arg.subj_id, &entry)
                       || rsbac_get_owner(&caller)
                       || (   (entry.owner != caller)
                           && (entry.type != ACLG_GLOBAL)
                          )
                      )
                      return(-RSBAC_EINVALIDVALUE);
                  }
                break;
              #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
              case ACLS_ROLE:
                if(k_arg.subj_id > RSBAC_RC_MAX_ROLE)
                  return(-RSBAC_EINVALIDVALUE);
                break;
              #endif
              default:
                return(-RSBAC_EINVALIDVALUE);
            }
        }
        
      switch (k_arg.target)
        {
          case T_FILE:
            if(k_arg.name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(k_arg.name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err= -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(k_arg.name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                    && !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.file.device = t_dentry->d_inode->i_dev;
                tid.file.inode  = t_dentry->d_inode->i_ino;
                tid.file.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DIR:
            if(k_arg.name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(k_arg.name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(k_arg.name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
                  { /* This is no dir */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
                tid.dir.inode  = t_dentry->d_inode->i_ino;
                tid.dir.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DEV:
            if(k_arg.name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(k_arg.name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(k_arg.name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* fill target id and call internal function */
                if(S_ISBLK(t_dentry->d_inode->i_mode))
                  tid.dev.type = D_block;
                else
                  tid.dev.type = D_char;
                tid.dev.id  = t_dentry->d_inode->i_rdev;
              }
            else
              {
                tid.dev.type = D_none;
                tid.dev.id = 0;
              }
            break;

          default:
            return -RSBAC_EINVALIDTARGET;
        }
      /* call acl function */
      switch(call)
        {
          case ACLC_set_acl_entry:
            err = rsbac_acl_sys_set_acl_entry(k_arg.target,
                                              tid,
                                              k_arg.subj_type,
                                              k_arg.subj_id,
                                              k_arg.rights);
            break;
          case ACLC_remove_acl_entry:
            err = rsbac_acl_sys_remove_acl_entry(k_arg.target,
                                                 tid,
                                                 k_arg.subj_type,
                                                 k_arg.subj_id);
            break;
          case ACLC_remove_acl:
            err = rsbac_acl_sys_remove_acl(k_arg.target,
                                           tid);
            break;
          case ACLC_add_to_acl_entry:
            err = rsbac_acl_sys_add_to_acl_entry(k_arg.target,
                                                 tid,
                                                 k_arg.subj_type,
                                                 k_arg.subj_id,
                                                 k_arg.rights);
            break;
          case ACLC_remove_from_acl_entry:
            err = rsbac_acl_sys_remove_from_acl_entry(k_arg.target,
                                                      tid,
                                                      k_arg.subj_type,
                                                      k_arg.subj_id,
                                                      k_arg.rights);
            break;
          case ACLC_set_mask:
            err = rsbac_acl_sys_set_mask(k_arg.target,
                                         tid,
                                         k_arg.rights);
            break;

          default:
            err=-RSBAC_EINVALIDREQUEST;
        }

out_dput:
      if(need_put)
        #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
        {
          dput(t_dentry);
          unlock_kernel();
        }
        #else
        path_release(&nd);
        #endif
out:
      return(err);
#else
      return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_n() */

/************************************************************************** */

asmlinkage int sys_rsbac_acl_get_rights (struct rsbac_acl_syscall_arg_t   * arg,
                                                rsbac_acl_rights_vector_t * rights_p,
                                                u_int                     effective)
    { 
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      struct rsbac_acl_syscall_arg_t k_arg;
      rsbac_acl_rights_vector_t k_rights = 0;
      int   err = 0;
      
      if(!arg || !rights_p)
        return(-RSBAC_EINVALIDPOINTER);
      /* get values from user space */
      rsbac_get_user((u_char *) &k_arg, (u_char *) arg, sizeof(k_arg) );

      if(k_arg.target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
/*      printk(KERN_DEBUG "sys_rsbac_acl_get_rights(): target = %u, subj_type = %u, subj_id = %u!\n",
             k_arg.target, k_arg.subj_type, k_arg.subj_id); */
      switch(k_arg.subj_type)
        {
          case ACLS_USER:
            break;
          case ACLS_GROUP:
            if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE)
              {
                struct rsbac_acl_group_entry_t entry;
                       rsbac_uid_t caller;

                if(   rsbac_acl_get_group_entry(k_arg.subj_id, &entry)
                   || rsbac_get_owner(&caller)
                   || (   (entry.owner != caller)
                       && (entry.type != ACLG_GLOBAL)
                      )
                  )
                  return(-RSBAC_EINVALIDVALUE);
              }
            break;
          case ACLS_ROLE:
          #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
            if(k_arg.subj_id > RSBAC_RC_MAX_ROLE)
              return(-RSBAC_EINVALIDVALUE);
          #endif
            break;
          default:
            printk(KERN_DEBUG "sys_rsbac_acl_get_rights(): Invalid subject type %u!\n", k_arg.subj_type);
            return(-RSBAC_EINVALIDVALUE);
        }

      /* call acl function */
      err = rsbac_acl_sys_get_rights(k_arg.target,
                                     k_arg.tid,
                                     k_arg.subj_type,
                                     k_arg.subj_id,
                                     &k_rights,
                                     effective);
      if(!err)
        {
          err = rsbac_put_user((u_char *) &k_rights, (u_char *) rights_p, sizeof(k_rights) );
        }
      return (err);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_get_rights() */


asmlinkage int sys_rsbac_acl_get_rights_n(struct rsbac_acl_syscall_n_arg_t * arg,
                                                 rsbac_acl_rights_vector_t * rights_p,
                                                 u_int                     effective)
    {
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      struct dentry * t_dentry = NULL;
      boolean need_put = FALSE;
      int     err = 0;
      union rsbac_target_id_t  tid;
      struct rsbac_acl_syscall_n_arg_t k_arg;
      rsbac_acl_rights_vector_t k_rights = 0;
      
      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif

      if(!arg || !rights_p)
        return(-RSBAC_EINVALIDPOINTER);
      /* get values from user space */
      rsbac_get_user((u_char *) &k_arg, (u_char *) arg, sizeof(k_arg) );

      if(k_arg.target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
      switch(k_arg.subj_type)
        {
          case ACLS_USER:
            break;
          case ACLS_GROUP:
            if(k_arg.subj_id != RSBAC_ACL_GROUP_EVERYONE)
              {
                struct rsbac_acl_group_entry_t entry;
                       rsbac_uid_t caller;

                if(   rsbac_acl_get_group_entry(k_arg.subj_id, &entry)
                   || rsbac_get_owner(&caller)
                   || (   (entry.owner != caller)
                       && (entry.type != ACLG_GLOBAL)
                      )
                  )
                  return(-RSBAC_EINVALIDVALUE);
              }
            break;
          case ACLS_ROLE:
          #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
            if(k_arg.subj_id > RSBAC_RC_MAX_ROLE)
              return(-RSBAC_EINVALIDVALUE);
          #endif
            break;
          default:
            return(-RSBAC_EINVALIDVALUE);
        }
        
      switch (k_arg.target)
        {
          case T_FILE:
            if(k_arg.name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(k_arg.name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err= -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(k_arg.name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_rights_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                    && !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.file.device = t_dentry->d_inode->i_dev;
                tid.file.inode  = t_dentry->d_inode->i_ino;
                tid.file.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DIR:
            if(k_arg.name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(k_arg.name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(k_arg.name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_rights_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
                  { /* This is no dir */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
                tid.dir.inode  = t_dentry->d_inode->i_ino;
                tid.dir.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DEV:
            if(k_arg.name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(k_arg.name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(k_arg.name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_rights_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* fill target id and call internal function */
                if(S_ISBLK(t_dentry->d_inode->i_mode))
                  tid.dev.type = D_block;
                else
                  tid.dev.type = D_char;
                tid.dev.id  = t_dentry->d_inode->i_rdev;
              }
            else
              {
                tid.dev.type = D_none;
                tid.dev.id = 0;
              }
            break;

          default:
            return -RSBAC_EINVALIDTARGET;
        }

      /* call acl function */
      err = rsbac_acl_sys_get_rights(k_arg.target,
                                     tid,
                                     k_arg.subj_type,
                                     k_arg.subj_id,
                                     &k_rights,
                                     effective);

out_dput:
      if(need_put)
        #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
        {
          dput(t_dentry);
          unlock_kernel();
        }
        #else
        path_release(&nd);
        #endif
out:
      if(!err)
        {
          rsbac_put_user((u_char *) &k_rights, (u_char *) rights_p, sizeof(k_rights) );
        }
      return(err);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_get_rights_n() */

/************************************************************************** */

asmlinkage int sys_rsbac_acl_get_tlist (enum   rsbac_target_t              target,
                                        union  rsbac_target_id_t         * tid,
                                        struct rsbac_acl_entry_t           entry_array[],
                                               u_int                       maxnum)
    { 
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      union  rsbac_target_id_t k_tid;
      struct rsbac_acl_entry_t k_entry_array[maxnum];
             int   err = 0;
      
      if(!tid || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
      if(!entry_array)
        return(-RSBAC_EINVALIDPOINTER);
      if(!maxnum)
        return(-RSBAC_EINVALIDVALUE);
        
      /* get values from user space */
      rsbac_get_user((u_char *) &k_tid, (u_char *) tid, sizeof(k_tid) );

      /* call acl function */
      err = rsbac_acl_sys_get_tlist(target, k_tid, k_entry_array, maxnum);
      if(err>0)
        {
          rsbac_put_user((u_char *) &k_entry_array,
                         (u_char *) entry_array,
                         err * sizeof(k_entry_array[0]) );
        }
      return (err);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_get_tlist() */

asmlinkage int sys_rsbac_acl_get_tlist_n(enum   rsbac_target_t      target,
                                         char                     * t_name,
                                         struct rsbac_acl_entry_t   entry_array[],
                                                u_int               maxnum)
    {
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      struct dentry * t_dentry = NULL;
      struct rsbac_acl_entry_t k_entry_array[maxnum];
      boolean need_put = FALSE;
      int     err = 0;
      union rsbac_target_id_t  tid;
      
      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif
        
      if(target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
      if(!entry_array)
        return(-RSBAC_EINVALIDPOINTER);

      switch (target)
        {
          case T_FILE:
            if(t_name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(t_name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err= -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(t_name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_tlist_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                    && !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.file.device = t_dentry->d_inode->i_dev;
                tid.file.inode  = t_dentry->d_inode->i_ino;
                tid.file.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DIR:
            if(t_name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(t_name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(t_name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_tlist_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
                  { /* This is no dir */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
                tid.dir.inode  = t_dentry->d_inode->i_ino;
                tid.dir.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DEV:
            if(t_name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(t_name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(t_name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_tlist_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* fill target id and call internal function */
                if(S_ISBLK(t_dentry->d_inode->i_mode))
                  tid.dev.type = D_block;
                else
                  tid.dev.type = D_char;
                tid.dev.id  = t_dentry->d_inode->i_rdev;
              }
            else
              {
                tid.dev.type = D_none;
                tid.dev.id = 0;
              }
            break;

          default:
            return -RSBAC_EINVALIDTARGET;
        }
      /* call ACL function */
      err = rsbac_acl_sys_get_tlist(target, tid, k_entry_array, maxnum);

out_dput:
      if(need_put)
      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
        {
          dput(t_dentry);
          unlock_kernel();
        }
      #else
        path_release(&nd);
      #endif
out:
      if(err>0)
        {
          rsbac_put_user((u_char *) &k_entry_array,
                         (u_char *) entry_array,
                         err * sizeof(k_entry_array[0]) );
        }
      return(err);

#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_get_tlist_n() */

/************************************************************************** */

asmlinkage int sys_rsbac_acl_get_mask (enum   rsbac_target_t              target,
                                       union  rsbac_target_id_t         * tid,
                                              rsbac_acl_rights_vector_t * mask_p)
    { 
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      union  rsbac_target_id_t k_tid;
             rsbac_acl_rights_vector_t k_mask;
             int   err = 0;
      
      if(!tid || (target >= T_NONE))
        return(-RSBAC_EINVALIDTARGET);
      if(!mask_p)
        return(-RSBAC_EINVALIDPOINTER);

      /* get values from user space */
      rsbac_get_user((u_char *) &k_tid, (u_char *) tid, sizeof(k_tid) );

      /* call acl function */
      err = rsbac_acl_sys_get_mask(target, k_tid, &k_mask);
      if(!err)
        {
          rsbac_put_user((u_char *) &k_mask,
                         (u_char *) mask_p,
                         sizeof(k_mask) );
        }
      return (err);
#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_get_mask() */

asmlinkage int sys_rsbac_acl_get_mask_n(enum rsbac_target_t              target,
                                             char                      * t_name,
                                             rsbac_acl_rights_vector_t * mask_p)
    {
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      struct dentry * t_dentry = NULL;
      rsbac_acl_rights_vector_t k_mask;
      boolean need_put = FALSE;
      int     err = 0;
      union rsbac_target_id_t  tid;

      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
      struct nameidata nd;
      #endif
      
      if(target >= T_NONE)
        return(-RSBAC_EINVALIDTARGET);
      if(!mask_p)
        return(-RSBAC_EINVALIDPOINTER);
        

      switch (target)
        {
          case T_FILE:
            if(t_name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(t_name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err= -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(t_name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_mask_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISREG(t_dentry->d_inode->i_mode))
                    && !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.file.device = t_dentry->d_inode->i_dev;
                tid.file.inode  = t_dentry->d_inode->i_ino;
                tid.file.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DIR:
            if(t_name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(t_name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(t_name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_mask_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                if ( !(S_ISDIR(t_dentry->d_inode->i_mode)) )
                  { /* This is no dir */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                tid.dir.device = t_dentry->d_inode->i_sb->s_dev;
                tid.dir.inode  = t_dentry->d_inode->i_ino;
                tid.dir.dentry_p = t_dentry;
              }
            else
              {
                tid.file.device = 0;
                tid.file.inode  = 0;
                tid.file.dentry_p = NULL;
              }
            break;

          case T_DEV:
            if(t_name)
              {
                #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
                lock_kernel();
                t_dentry = lookup_dentry(t_name,NULL,0);
                if (IS_ERR(t_dentry))
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    unlock_kernel();
                    goto out;
                  }
                #else
                if ((err = user_path_walk_link(t_name, &nd)))
                  {
                    if (rsbac_debug_aef_acl)
                      printk(KERN_DEBUG "sys_rsbac_acl_get_mask_n(): call to user_path_walk_link() returned %i\n", err);
                    goto out;
                   }
                t_dentry = nd.dentry;
                #endif
                need_put = TRUE;
                if (!t_dentry->d_inode)
                  {
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* is inode of type file or block/char device? */
                if (   !(S_ISBLK(t_dentry->d_inode->i_mode))
                    && !(S_ISCHR(t_dentry->d_inode->i_mode)) )
                  { /* This is no file or device */
                    err = -RSBAC_EINVALIDTARGET;
                    goto out_dput;
                  }
                /* fill target id and call internal function */
                if(S_ISBLK(t_dentry->d_inode->i_mode))
                  tid.dev.type = D_block;
                else
                  tid.dev.type = D_char;
                tid.dev.id  = t_dentry->d_inode->i_rdev;
              }
            else
              {
                tid.dev.type = D_none;
                tid.dev.id = 0;
              }
            break;

          default:
            return -RSBAC_EINVALIDTARGET;
        }
      /* call ACL function */
      err = rsbac_acl_sys_get_mask(target, tid, &k_mask);

out_dput:
      if(need_put)
        #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
        {
          dput(t_dentry);
          unlock_kernel();
        }
        #else
        path_release(&nd);
        #endif
out:
      if(!err)
        {
          rsbac_put_user((u_char *) &k_mask,
                         (u_char *) mask_p,
                         sizeof(k_mask) );
        }
      return(err);

#else
    return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl_get_mask_n() */

/********  ACL groups *********/

asmlinkage int sys_rsbac_acl_group(enum  rsbac_acl_group_syscall_type_t call,
                                   union rsbac_acl_group_syscall_arg_t * arg_p)
    { 
#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
      union rsbac_acl_group_syscall_arg_t k_arg;
      int   err = 0;

      if(call >= ACLGS_none)
        return(-RSBAC_EINVALIDREQUEST);
      if(!arg_p)
        return(-RSBAC_EINVALIDPOINTER);

      /* get values from user space */
      err = rsbac_get_user((u_char *) &k_arg, (u_char *) arg_p, sizeof(k_arg) );

      /* call acl function */
      if(err >= 0)
        err = rsbac_acl_sys_group(call, k_arg);
      return (err);
#else
      return (-RSBAC_EINVALIDREQUEST);
#endif    
    };      /* end of sys_rsbac_acl() */


/************************************************* */
/*             DEBUG/LOG functions                 */
/************************************************* */

asmlinkage int sys_rsbac_adf_log_switch(enum rsbac_adf_request_t target,
                                        enum rsbac_log_level_t   value)
  {
    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if ((value != LL_none) && (value != LL_denied) && (value != LL_full))
      return (-RSBAC_EINVALIDVALUE);
    if(target >= R_NONE)
      return(-RSBAC_EINVALIDTARGET);
    /* call ADF */
    if (rsbac_debug_aef)
      printk(KERN_DEBUG "sys_rsbac_adf_log_switch(): calling ADF\n");
    rsbac_target_id.dummy = 0;
    rsbac_attribute_value.request = target;
    if (!rsbac_adf_request(R_SWITCH_LOG,
                           current->pid,
                           T_NONE,
                           rsbac_target_id,
                           A_request,
                           rsbac_attribute_value))
             {
               return -EPERM;
             }
    if (rsbac_debug_aef)
      {
        char * request_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        if(request_name)
          {
            get_request_name(request_name,target);
              printk(KERN_DEBUG "sys_rsbac_adf_log_switch(): switching RSBAC module logging for request %s (No. %i) to %i!\n",
                     request_name, target, value);
          }
      }
    rsbac_adf_log_switch(target,value);
    return(0);
  };

/*
 * Commands to sys_rsbac_log:
 *
 * 	0 -- Close the log.  Currently a NOP.
 * 	1 -- Open the log. Currently a NOP.
 * 	2 -- Read from the log.
 * 	3 -- Read up to the last 4k of messages in the ring buffer.
 * 	4 -- Read and clear last 4k of messages in the ring buffer
 * 	5 -- Clear ring buffer.
 */
asmlinkage int sys_rsbac_log(int type,
                             char * buf,
                             int len)
  {
#if defined(CONFIG_RSBAC_RMSG)
    /* lock_kernel is done in rsbac_log */
    return(rsbac_log(type,buf,len));
#else
    return(0);
#endif /* RMSG */
  };

/* end of syscalls.c */
