/************************************************* */
/* Rule Set Based Access Control                   */
/* Implementation of the Access Control Decision   */
/* Facility (ADF) - Main file main.c               */
/*                                                 */
/* Author and (c) 1999,2000: Amon Ott              */
/*                                                 */
/* Last modified: 10/Nov/2000                      */
/************************************************* */

#include <linux/string.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <rsbac/types.h>
#include <rsbac/aci.h>
#include <rsbac/adf.h>
#include <rsbac/adf_main.h>
#include <rsbac/error.h>
#include <rsbac/helpers.h>
#include <rsbac/getname.h>

#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT
#include <linux/nfs_fs.h>
#include <linux/coda_psdev.h>
#include <linux/ncp_fs.h>
#include <linux/smb.h>
#endif

#ifdef CONFIG_RSBAC_SECDEL
#include <linux/types.h>
#include <linux/dcache.h>
#include <asm/uaccess.h>
#endif /* SECDEL */

#ifndef NULL
#define NULL ((void *) 0)
#endif

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

u_long rsbac_adf_request_count[T_NONE+1] = {0,0,0,0,0,0,0,0};
u_long rsbac_adf_set_attr_count[T_NONE+1] = {0,0,0,0,0,0,0,0};
#ifdef CONFIG_RSBAC_XSTATS
u_long rsbac_adf_request_xcount[T_NONE+1][R_NONE];
u_long rsbac_adf_set_attr_xcount[T_NONE+1][R_NONE];
#endif

/******* MAC ********/
#ifdef CONFIG_RSBAC_MAC
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_mac = TRUE;
#endif
#endif  /* MAC */

/******* FC ********/
#ifdef CONFIG_RSBAC_FC
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_fc = TRUE;
#endif
#endif  /* FC */

/******* SIM ********/
#ifdef CONFIG_RSBAC_SIM
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_sim = TRUE;
#endif
#endif  /* SIM */

/******* PM ********/
#ifdef CONFIG_RSBAC_PM
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_pm = TRUE;
#endif
#endif  /* PM */

/******* MS ********/
#ifdef CONFIG_RSBAC_MS
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_ms = TRUE;
#endif
#endif  /* MS */

/******* FF ********/
#ifdef CONFIG_RSBAC_FF
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_ff = TRUE;
#endif
#endif  /* FF */

/******* RC ********/
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_rc = TRUE;
#endif
#endif  /* RC */

/****** AUTH *******/
#ifdef CONFIG_RSBAC_AUTH
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_auth = TRUE;
#endif
#endif  /* AUTH */

/****** ACL *******/
#ifdef CONFIG_RSBAC_ACL
#ifdef CONFIG_RSBAC_SWITCH
boolean rsbac_switch_acl = TRUE;
#endif
#endif  /* ACL */


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

static enum rsbac_adf_req_ret_t
    adf_and_plus(enum rsbac_adf_req_ret_t res1,
                 enum rsbac_adf_req_ret_t res2)
  {
    switch (res1)
      {
        case GRANTED:     if (res2 == DO_NOT_CARE)
                            return (GRANTED);
                          else
                            return (res2);
        case NOT_GRANTED: if (res2 == UNDEFINED)
                            return (UNDEFINED);
                          else
                            return (NOT_GRANTED);
        case DO_NOT_CARE: return (res2);
        default:          return (UNDEFINED);
      }
  };


/************************************************* */
/*          Externally visible functions           */
/************************************************* */

/* Init function, calls inits for all sub-modules  */

void __init rsbac_init_adf(void)
  {
    #ifdef CONFIG_RSBAC_REG
    rsbac_reg_init();
    #endif
  };

/*********************************************************************/
/* rsbac_adf_request()                                               */
/* This function is the main decision function, called from the AEF. */

#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_adf_request_int);
#endif
enum rsbac_adf_req_ret_t
   rsbac_adf_request_int(enum  rsbac_adf_request_t     request,
                               rsbac_pid_t             caller_pid,
                         enum  rsbac_target_t          target,
                         union rsbac_target_id_t       tid,
                         enum  rsbac_attribute_t       attr,
                         union rsbac_attribute_value_t attr_val,
                         enum  rsbac_switch_target_t   ignore_module)
  {
    union rsbac_target_id_t        i_tid;
    union rsbac_attribute_value_t  i_attr_val;
          rsbac_uid_t              owner=0;
    int error=0,tmperr=0;
    enum rsbac_adf_req_ret_t   result = DO_NOT_CARE;
#ifndef CONFIG_RSBAC_MAINT
    enum rsbac_adf_req_ret_t   mod_result[SW_NONE] = {
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE,
                                   DO_NOT_CARE
                                 };
#endif
    boolean do_log = FALSE;
    boolean log_on_request = TRUE;
/* only if individual logging is enabled */
#ifdef CONFIG_RSBAC_IND_LOG
    union rsbac_attribute_value_t  i_attr_val2;
    enum rsbac_log_level_t log_level;
#endif
#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT
    struct super_block * sb_p;
#endif
#ifdef CONFIG_RSBAC_REG
    int i;
#endif

/* No decision possible before init (called at boot time) -> don't care */
    if (!rsbac_is_initialized())
      return(DO_NOT_CARE);

/* Always granted for kernel (pid 0) */
    if (!caller_pid)
      return(GRANTED);

/* Checking base values */
    if(   request >= R_NONE
       || target > T_NONE
       || attr > A_none)
      {
        printk(KERN_WARNING
               "rsbac_adf_request(): called with invalid request, target or attribute\n");
        return(NOT_GRANTED);
      }

/* Getting basic information about this request */

    /* only useful for real process, not idle or init */
    if (caller_pid > 1)
      {
        tmperr = rsbac_get_owner(&owner);
        if(tmperr)
          {
            printk(KERN_DEBUG
                   "rsbac_adf_request(): caller_pid %i, RSBAC not initialized, returning DO_NOT_CARE",
                   caller_pid);
            return(DO_NOT_CARE);      /* Startup-Sequence (see above) */
          }
      }
    else  /* caller_pid = 1 -> init, always owned by root */
      owner = 0;


/******************************************************/
/* General work for all modules - before module calls */
    /* test target on rsbac_internal: get its sec_level */
    switch(target)
      {
        case T_FILE:
        case T_DIR:
#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT
          if (   ((sb_p = get_super(tid.file.device)))
              && (   (sb_p->s_magic == NFS_SUPER_MAGIC)
                  || (sb_p->s_magic == CODA_SUPER_MAGIC)
                  || (sb_p->s_magic == NCP_SUPER_MAGIC)
                  || (sb_p->s_magic == SMB_SUPER_MAGIC)
                 )
             )
            {
              result = DO_NOT_CARE;
              goto log;
            }
#endif
          if(tid.file.device == 0)
            {
              if (   (rsbac_debug_adf_default == 2)
                  || rsbac_debug_aef
                 )
                printk(KERN_DEBUG
                       "rsbac_adf_request(): device is 0 for request %i, target type %i, returning DO_NOT_CARE!\n",
                       request,target);
              result = DO_NOT_CARE;
              goto log;
            }
          if ((tmperr = rsbac_get_attr(target,
                                       tid,
                                       A_security_level,
                                       &i_attr_val,
                                       TRUE) ))
            {
              if(tmperr == -RSBAC_EINVALIDDEV)
                {
                  printk(KERN_WARNING
                         "rsbac_adf_request(): rsbac_get_attr() for security_level returned EINVALIDDEV!\n");
                  return(DO_NOT_CARE);  /* last calls on shutdown */
                }
              else
                {
                  printk(KERN_WARNING
                         "rsbac_adf_request(): rsbac_get_attr() for security_level returned error %i!\n",
                         tmperr);
                  return(NOT_GRANTED);  /* something weird happened */
                }
            }
          /* no access to rsbac_internal objects is granted in any case */
          if (i_attr_val.security_level == SL_rsbac_internal)
            {
              if(request != R_GET_STATUS_DATA)
                {
                  printk(KERN_WARNING
                         "rsbac_adf_request(): trial to access object declared RSBAC-internal!\n");
                  result = NOT_GRANTED;
                }
            }
        default:
      }
      
/**********************************************************/
/* calling all decision modules, building a common result */
/* first, check for valid request/target combination      */
/* (no need to call check, if already undefined)          */
if(result != UNDEFINED)
  result = adf_and_plus(result,rsbac_adf_request_check(request,
                                                       caller_pid,
                                                       target,
                                                       tid,
                                                       attr,
                                                       attr_val,
                                                       owner) );

/******* MAC ********/
#ifdef CONFIG_RSBAC_MAC
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_mac)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != MAC)
    )
    {
      mod_result[MAC] = rsbac_adf_request_mac(request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[MAC]);
    }
#endif  /* MAC */

/******* FC ********/
#ifdef CONFIG_RSBAC_FC
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_fc)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != FC)
    )
    {
      mod_result[FC]  = rsbac_adf_request_fc (request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[FC]);
    }
#endif  /* FC */

/******* SIM ********/
#ifdef CONFIG_RSBAC_SIM
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_sim)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != SIM)
    )
    {
      mod_result[SIM] = rsbac_adf_request_sim(request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[SIM]);
    }
#endif  /* SIM */

/******* PM ********/
#ifdef CONFIG_RSBAC_PM
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_pm)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != PM)
    )
    {
      mod_result[PM]  = rsbac_adf_request_pm (request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[PM]);
    }
#endif  /* PM */

/******* MS ********/
#ifdef CONFIG_RSBAC_MS
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_ms)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != MS)
    )
    {
      mod_result[MS]  = rsbac_adf_request_ms (request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[MS]);
    }
#endif  /* MS */

/******* FF ********/
#ifdef CONFIG_RSBAC_FF
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_ff)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != FF)
    )
    {
      mod_result[FF]  = rsbac_adf_request_ff (request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[FF]);
    }
#endif  /* FF */

/******* RC ********/
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_rc)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != RC)
    )
    {
      mod_result[RC]  = rsbac_adf_request_rc (request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[RC]);
    }
#endif  /* RC */

/****** AUTH *******/
#ifdef CONFIG_RSBAC_AUTH
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_auth)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != AUTH)
    )
    {
      mod_result[AUTH]= rsbac_adf_request_auth(request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[AUTH]);
    }
#endif  /* AUTH */

/****** REG *******/
#ifdef CONFIG_RSBAC_REG
for(i=0;i<RSBAC_REG_NR_ENTRIES;i++)
  {
    if(   rsbac_reg_entry[i].request_func
    #ifdef CONFIG_RSBAC_SWITCH
       && rsbac_reg_entry[i].switch_on
    #endif
      )
      /* no need to call module, if already undefined or to be ignored */
      if(   (result != UNDEFINED)
         && (ignore_module != REG)
        )
        mod_result[REG] = adf_and_plus(mod_result[REG],
                              rsbac_reg_entry[i].request_func (request,
                                                               caller_pid,
                                                               target,
                                                               tid,
                                                               attr,
                                                               attr_val,
                                                               owner) );
  }
result = adf_and_plus(result, mod_result[REG]);
#endif  /* REG */

/****** ACL *******/
#ifdef CONFIG_RSBAC_ACL
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_acl)
#endif
  /* no need to call module, if already undefined or to be ignored */
  if(   (result != UNDEFINED)
     && (ignore_module != AUTH)
    )
    {
      mod_result[ACL] = rsbac_adf_request_acl(request,
                                              caller_pid,
                                              target,
                                              tid,
                                              attr,
                                              attr_val,
                                              owner);
      result = adf_and_plus(result, mod_result[ACL]);
    }
#endif  /* ACL */

/* log based on process owner */
#ifdef CONFIG_RSBAC_IND_USER_LOG
    i_tid.user = owner;
    if (rsbac_get_attr(T_USER,
                       i_tid,
                       A_log_user_based,
                       &i_attr_val,
                       FALSE))
      {
        printk(KERN_WARNING
               "rsbac_adf_request(): rsbac_get_attr() for log_user_based returned error!\n");
      }
    else
      {
        if(((rsbac_request_vector_t) 1 << request) & i_attr_val.log_user_based) 
          do_log = TRUE;
      }
#endif /* CONFIG_RSBAC_IND_USER_LOG */

/* log based on program */
#ifdef CONFIG_RSBAC_IND_PROG_LOG
    if(!do_log)
      {
        i_tid.process = caller_pid;
        if (rsbac_get_attr(T_PROCESS,
                           i_tid,
                           A_log_program_based,
                           &i_attr_val,
                           FALSE))
          {
            printk(KERN_WARNING
                   "rsbac_adf_request(): rsbac_get_attr() for log_program_based returned error!\n");
          }
        else
          {
            if(((rsbac_request_vector_t) 1 << request) & i_attr_val.log_program_based) 
              do_log = TRUE;
          }
      }
#endif /* CONFIG_RSBAC_IND_PROG_LOG */

/*****************************************************/
/* General work for all modules - after module calls */
    switch(request)
      {
        case R_TERMINATE:
            if (target == T_PROCESS)
              rsbac_remove_target(T_PROCESS,tid);
            break;
        default:
      }

/* logging request on info level, if requested by file/dir/dev attributes */
/* log_array_low/high, or, if that is requested, if enabled for this request */
/* type (attributes state level, or that request based level is to be taken) */
/* loglevel 2: log everything */
/* loglevel 1: log, if denied */
/* loglevel 0: log nothing */

#ifdef CONFIG_RSBAC_IND_LOG /* only if individual logging is enabled */
    /* if file/dir/dev, depend log on log_arrays */
    /* (but not for file.device = 0) */
    /* log_on_request is TRUE */
    if(   !do_log
       && (   (   (   (target == T_FILE)
                   || (target == T_DIR))
               && tid.file.device
              )
           || (target == T_DEV)
          )
      )
      {
        if (rsbac_get_attr(target,
                           tid,
                           A_log_array_low,
                           &i_attr_val,
                           FALSE))
          {
            printk(KERN_WARNING
                   "rsbac_adf_request(): rsbac_get_attr() for log_array_low returned error!\n");
          }
        else
          {
            if (rsbac_get_attr(target,
                               tid,
                               A_log_array_high,
                               &i_attr_val2,
                               FALSE))
              {
                printk(KERN_WARNING
                       "rsbac_adf_request(): rsbac_get_attr() for log_array_high returned error!\n");
              }
            else
              { /* ll = low-bit for request | (high-bit for request as bit 1) */
                /* WARNING: we deal with u64 here, only logical operations and */
                /* shifts work correctly! */
                log_level =   ((i_attr_val.log_array_low   >> request) & 1)
                          | ( ((i_attr_val2.log_array_high >> request) & 1) << 1);
                if (   log_level == LL_full
                    || (   log_level == LL_denied
                        && (result == NOT_GRANTED
                            || result == UNDEFINED)) )
                  {
                    do_log = TRUE;
                  }
                if(log_level != LL_request)
                  log_on_request = FALSE;
              }
          }
      }
#endif /* CONFIG_RSBAC_IND_LOG */

log:
    /* if enabled, try request based log level */
    if (   !do_log
        && log_on_request
        && (   rsbac_debug_adf[request] == LL_full
            || (   rsbac_debug_adf[request] == LL_denied
                && (result == NOT_GRANTED
                    || result == UNDEFINED)) ) )
      do_log = TRUE;

    if(do_log)
      {
        char * request_name;
        char * res_name;
        char * res_mods;
        char * target_type_name;
        char * target_id_name;
        char * attr_name;
        char  command[17];
        rsbac_pseudo_t  pseudo = 0;

        /* Get owner's logging pseudo */
        if (rsbac_get_attr(T_USER,i_tid,A_pseudo,&i_attr_val,FALSE))
          {
            printk(KERN_WARNING
              "rsbac_adf_request(): rsbac_get_attr() for pseudo returned error %i",
              error);
            return(NOT_GRANTED);  /* something weird happened */
          }
        /* if pseudo is not registered, return attribute value is 0 (see later) */
        pseudo = i_attr_val.pseudo;

        /* kmalloc all memory */
        request_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        res_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        res_mods = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        target_type_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        #ifdef CONFIG_RSBAC_LOG_FULL_PATH
        target_id_name
         = kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN, GFP_KERNEL);
           /* max. path name len + some extra */
        #else
        target_id_name = kmalloc(2 * RSBAC_MAXNAMELEN, GFP_KERNEL);
           /* max. file name len + some extra */
        #endif
        attr_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);

        request_name[0] = (char) 0;
        target_type_name[0] = (char) 0;
        target_id_name[0] = (char) 0;
        attr_name[0] = (char) 0;
        res_name[0] = (char) 0;
        res_mods[0] = (char) 0;
        command[0] = (char) 0;
        get_request_name(request_name, request);
    #ifdef CONFIG_RSBAC_MAC
        if(result == mod_result[MAC])
          strcat(res_mods, " MAC");
    #endif
    #ifdef CONFIG_RSBAC_FC
        if(result == mod_result[FC])
          strcat(res_mods, " FC");
    #endif
    #ifdef CONFIG_RSBAC_SIM
        if(result == mod_result[SIM])
          strcat(res_mods, " SIM");
    #endif
    #ifdef CONFIG_RSBAC_PM
        if(result == mod_result[PM])
          strcat(res_mods, " PM");
    #endif
    #ifdef CONFIG_RSBAC_MS
        if(result == mod_result[MS])
          strcat(res_mods, " MS");
    #endif
    #ifdef CONFIG_RSBAC_FF
        if(result == mod_result[FF])
          strcat(res_mods, " FF");
    #endif
    #ifdef CONFIG_RSBAC_RC
        if(result == mod_result[RC])
          strcat(res_mods, " RC");
    #endif
    #ifdef CONFIG_RSBAC_AUTH
        if(result == mod_result[AUTH])
          strcat(res_mods, " AUTH");
    #endif
    #ifdef CONFIG_RSBAC_REG
        if(result == mod_result[REG])
          strcat(res_mods, " REG");
    #endif
    #ifdef CONFIG_RSBAC_ACL
        if(result == mod_result[ACL])
          strcat(res_mods, " ACL");
    #endif
        get_target_name(target_type_name, target, target_id_name, tid);
        get_attribute_name(attr_name, attr);
        get_result_name(res_name, result);
        if ((current) && (current->comm))
          {
            strncpy(command,current->comm,16);          
            command[16] = (char) 0;
          }

#ifdef CONFIG_RSBAC_RMSG
        /* if pseudo is set, its value is != 0, else -> use id */
        if (pseudo)
          rsbac_printk(KERN_INFO "rsbac_adf_request(): request %s, caller_pid %u, caller_prog_name %s, caller_pseudo %u, target-type %s, tid %s, attr %s, value %u, result %s by%s\n",
                   request_name, caller_pid, command, i_attr_val.pseudo, target_type_name, target_id_name, attr_name, attr_val.dummy, res_name, res_mods);
        else
          rsbac_printk(KERN_INFO "rsbac_adf_request(): request %s, caller_pid %u, caller_prog_name %s, caller_uid %u, target-type %s, tid %s, attr %s, value %u, result %s by%s\n",
                   request_name, caller_pid, command, owner, target_type_name, target_id_name, attr_name, attr_val.dummy, res_name, res_mods);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
        /* if pseudo is set, its value is != 0, else -> use id */
        if (pseudo)
          printk(KERN_INFO "rsbac_adf_request(): request %s, caller_pid %u, caller_prog_name %s, caller_pseudo %u, target-type %s, tid %s, attr %s, value %u, result %s by%s\n",
                   request_name, caller_pid, command, i_attr_val.pseudo, target_type_name, target_id_name, attr_name, attr_val.dummy, res_name, res_mods);
        else
          printk(KERN_INFO "rsbac_adf_request(): request %s, caller_pid %u, caller_prog_name %s, caller_uid %u, target-type %s, tid %s, attr %s, value %u, result %s by%s\n",
                   request_name, caller_pid, command, owner, target_type_name, target_id_name, attr_name, attr_val.dummy, res_name, res_mods);
#endif
        /* kfree all helper mem */
        kfree(request_name);
        kfree(res_name);
        kfree(res_mods);
        kfree(target_type_name);
        kfree(target_id_name);
        kfree(attr_name);
      }

/* UNDEFINED must never be returned -> change result */
    if(result == UNDEFINED)
      result = NOT_GRANTED;

/* count */
    rsbac_adf_request_count[target]++;
#ifdef CONFIG_RSBAC_XSTATS
    rsbac_adf_request_xcount[target][request]++;
#endif

/* return result */
    return(result); /* change for debugging! */
  }; /* end of rsbac_adf_request_int() */


/*********************************************************************/
/* rsbac_adf_request()                                               */
/* This function is the main decision function, called from the AEF. */
/* It is a simple wrapper to the internal function, setting          */
/* ignore_module to SW_NONE.                                         */

#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_adf_request);
#endif
enum rsbac_adf_req_ret_t
   rsbac_adf_request( enum  rsbac_adf_request_t     request,
                            rsbac_pid_t             caller_pid,
                      enum  rsbac_target_t          target,
                      union rsbac_target_id_t       tid,
                      enum  rsbac_attribute_t       attr,
                      union rsbac_attribute_value_t attr_val)
  {
    return(rsbac_adf_request_int(request,
                                 caller_pid,
                                 target,
                                 tid,
                                 attr,
                                 attr_val,
                                 SW_NONE));
  }

/*****************************************************************************/
/* If the request returned granted and the operation is performed,           */
/* the following function is called by the AEF to get all aci set correctly. */
/* The second instance of target specification is the new target, if one has */
/* been created, otherwise its values are ignored.                           */
/* It returns 0 on success and an error from error.h otherwise.              */

#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_adf_set_attr);
#endif
int  rsbac_adf_set_attr(
                      enum  rsbac_adf_request_t     request,
                            rsbac_pid_t             caller_pid,
                      enum  rsbac_target_t          target,
                      union rsbac_target_id_t       tid,
                      enum  rsbac_target_t          new_target,
                      union rsbac_target_id_t       new_tid,
                      enum  rsbac_attribute_t       attr,
                      union rsbac_attribute_value_t attr_val)
  {
    union rsbac_target_id_t i_tid;
    int   error = 0;
    boolean do_log = FALSE;
    boolean log_on_request = TRUE;
#ifdef CONFIG_RSBAC_IND_LOG /* only if individual logging is enabled */
    union rsbac_attribute_value_t i_attr_val,i_attr_val2;
    enum rsbac_log_level_t log_level;
#endif
#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT
    struct super_block * sb_p;
#endif
#ifdef CONFIG_RSBAC_REG
    int i;
#endif

/* No attribute setting possible before init (called at boot time) */

   if (!rsbac_is_initialized())
      return(0);

/* kernel (pid 0) is ignored */
    if (!caller_pid)
      return(0);

/* Checking base values */
    if(   request >= R_NONE
       || target > T_NONE
       || new_target > T_NONE
       || attr > A_none)
      {
        printk(KERN_WARNING
               "rsbac_adf_set_attr(): called with invalid request, target or attribute\n");
        return(-RSBAC_EINVALIDVALUE);
      }

/* Getting basic information about this adf_set_attr-call */

    i_tid.user = RSBAC_NO_USER;
    /* only useful for real process, not idle or init */
    if (caller_pid > 1)
      {
        error = rsbac_get_owner(&i_tid.user);
        if(error)
          {
            printk(KERN_DEBUG
                   "rsbac_adf_set_attr(): caller_pid %i, RSBAC not initialized, returning 0",
                   caller_pid);
            return(0);      /* Startup-Sequence (see above) */
          }
      }
    else /* caller_pid = 1  -> init -> owner = root */
      i_tid.user = 0;

/*************************************************/
/* General work for all modules - before modules */
#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT
    if (   (   (target == T_FILE)
            || (target == T_DIR)
           )
        && ((sb_p = get_super(tid.file.device)))
        && (   (sb_p->s_magic == NFS_SUPER_MAGIC)
            || (sb_p->s_magic == CODA_SUPER_MAGIC)
            || (sb_p->s_magic == NCP_SUPER_MAGIC)
            || (sb_p->s_magic == SMB_SUPER_MAGIC)
           )
       )
      {
        error = 0;
        goto log;
      }
#endif

/**********************************************************/
/* calling all decision modules, building a common result */
/* first, check for valid request/target combination      */

error |= rsbac_adf_set_attr_check(request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
if(error)
  goto general_work;

/******* MAC ********/
#ifdef CONFIG_RSBAC_MAC
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_mac)
#endif
  error |= rsbac_adf_set_attr_mac(request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* MAC */

/******* FC ********/
#ifdef CONFIG_RSBAC_FC
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_fc)
#endif
  error |= rsbac_adf_set_attr_fc (request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* FC */

/******* SIM ********/
#ifdef CONFIG_RSBAC_SIM
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_sim)
#endif
  error |= rsbac_adf_set_attr_sim(request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* SIM */

/******* PM ********/
#ifdef CONFIG_RSBAC_PM
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_pm)
#endif
  error |= rsbac_adf_set_attr_pm (request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* PM */

/******* MS ********/
#ifdef CONFIG_RSBAC_MS
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_ms)
#endif
  error |= rsbac_adf_set_attr_ms (request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* MS */

/******* FF ********/
#ifdef CONFIG_RSBAC_FF
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_ff)
#endif
  error |= rsbac_adf_set_attr_ff (request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* FF */

/******* RC ********/
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_rc)
#endif
  error |= rsbac_adf_set_attr_rc (request,
                                  caller_pid,
                                  target,
                                  tid,
                                  new_target,
                                  new_tid,
                                  attr,
                                  attr_val,
                                  i_tid.user);
#endif  /* RC */

/****** AUTH *******/
#ifdef CONFIG_RSBAC_AUTH
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_auth)
#endif
  error |= rsbac_adf_set_attr_auth(request,
                                   caller_pid,
                                   target,
                                   tid,
                                   new_target,
                                   new_tid,
                                   attr,
                                   attr_val,
                                   i_tid.user);
#endif  /* AUTH */

/****** REG *******/
#ifdef CONFIG_RSBAC_REG
for(i=0;i<RSBAC_REG_NR_ENTRIES;i++)
  {
    if(   rsbac_reg_entry[i].set_attr_func
    #ifdef CONFIG_RSBAC_SWITCH
       && rsbac_reg_entry[i].switch_on
    #endif
      )
      /* no need to call module, if already undefined or to be ignored */
      error |= rsbac_reg_entry[i].set_attr_func (request,
                                                 caller_pid,
                                                 target,
                                                 tid,
                                                 new_target,
                                                 new_tid,
                                                 attr,
                                                 attr_val,
                                                 i_tid.user);
  }
#endif  /* REG */

/****** ACL *******/
#ifdef CONFIG_RSBAC_ACL
#ifdef CONFIG_RSBAC_SWITCH
if (rsbac_switch_acl)
#endif
  error |= rsbac_adf_set_attr_acl (request,
                                   caller_pid,
                                   target,
                                   tid,
                                   new_target,
                                   new_tid,
                                   attr,
                                   attr_val,
                                   i_tid.user);
#endif  /* ACL */


/* General work for all modules (after set_attr call) */
general_work:
    switch(request)
      {
        /* remove deleted item from rsbac data */
        case R_DELETE :
            switch (target)
              {
                case T_FILE:
                  /* Only remove file target on deletion of last link */
                  if (   (attr == A_nlink)
                      && (attr_val.nlink > 1))
                     break;
                case T_DIR:
                case T_IPC:
                  rsbac_remove_target(target,tid);
                  break;
                default:
                  break;
              }
            break;

#ifdef CONFIG_RSBAC_IND_PROG_LOG
        case R_CLONE:
            switch (target)
              {
                case T_PROCESS:
                  /* get program based log from old process */
                  if (rsbac_get_attr(target,
                                     tid,
                                     A_log_program_based,
                                     &i_attr_val,
                                     FALSE))
                    {
                      printk(KERN_WARNING
                             "rsbac_adf_request(): rsbac_get_attr() for log_program_based returned error!\n");
                    }
                  else
                    {
                      /* set program based log for new process */
                      if (rsbac_set_attr(new_target,
                                         new_tid,
                                         A_log_program_based,
                                         i_attr_val))
                        {
                          printk(KERN_WARNING
                                 "rsbac_adf_request(): rsbac_set_attr() for log_program_based returned error!\n");
                        }
                    }
                  break;

                default:
                  break;
              }
            break;

        case R_EXECUTE :
            switch (target)
              {
                case T_FILE:
                  /* get program based log from file */
                  if (rsbac_get_attr(target,
                                     tid,
                                     A_log_program_based,
                                     &i_attr_val,
                                     FALSE))
                    {
                      printk(KERN_WARNING
                             "rsbac_adf_request(): rsbac_get_attr() for log_program_based returned error!\n");
                    }
                  else
                    {
                      /* set program based log for process */
                      i_tid.process = caller_pid;
                      if (rsbac_set_attr(T_PROCESS,
                                         i_tid,
                                         A_log_program_based,
                                         i_attr_val))
                        {
                          printk(KERN_WARNING
                                 "rsbac_adf_request(): rsbac_set_attr() for log_program_based returned error!\n");
                        }
                    }
                  break;

                default:
                  break;
              }
            break;
#endif /* CONFIG_RSBAC_IND_PROG_LOG */

#ifdef CONFIG_RSBAC_USE_RSBAC_OWNER
        case R_CHANGE_OWNER:
            switch (target)
              {
                case T_PROCESS:
                  /* there must be a new owner specified / checked before */
                  /* set owner for process to new owner */
                  if (rsbac_set_attr(T_PROCESS,
                                     tid,
                                     A_owner,
                                     attr_val))
                    {
                      printk(KERN_WARNING "rsbac_adf_set_attr(): rsbac_set_attr() returned error!\n");
                      return(-RSBAC_EWRITEFAILED);
                    }
                  break;
                default:
              }
            break;
#endif /* CONFIG_RSBAC_USE_RSBAC_OWNER */

        default:
      }


/* logging request on info level, if requested by file/dir/dev attributes */
/* log_array_low/high, or, if that is requested, if enabled for this request */
/* type (attributes state level, or that request based level is to be taken) */
/* loglevel 2: log everything */
/* loglevel 1: log, if denied */
/* loglevel 0: log nothing */

#ifdef CONFIG_RSBAC_IND_LOG /* only if individual logging is enabled */
    /* if file/dir/dev, depend log on log_arrays */
    /* (but not for file.device = 0) */
    /* log_on_request is TRUE */
    if(   (   (   (target == T_FILE)
               || (target == T_DIR))
           && tid.file.device
          )
       || (target == T_DEV)
      )
      {
        if (rsbac_get_attr(target,
                           tid,
                           A_log_array_low,
                           &i_attr_val,
                           FALSE))
          {
            printk(KERN_WARNING
                   "rsbac_adf_set_attr(): rsbac_get_attr() for log_array_low returned error!\n");
          }
        else
          {
            if (rsbac_get_attr(target,
                               tid,
                               A_log_array_high,
                               &i_attr_val2,
                               FALSE))
              {
                printk(KERN_WARNING
                       "rsbac_adf_set_attr(): rsbac_get_attr() for log_array_high returned error!\n");
              }
            else
              { /* ll = low-bit for request | (high-bit for request as bit 1) */
                log_level =   ((i_attr_val.log_array_low   >> request) & 1)
                          | ( ((i_attr_val2.log_array_high >> request) & 1) << 1);
                if (   log_level == LL_full
                    || (   log_level == LL_denied
                        && error) )
                  {
                    do_log = TRUE;
                  }
                if(log_level != LL_request)
                  log_on_request = FALSE;
              }
          }
      }
#endif /* CONFIG_RSBAC_IND_LOG */

#ifdef CONFIG_RSBAC_NO_DECISION_ON_NETMOUNT
log:
#endif
    /* if enabled, try request based log level */
    if (log_on_request
        && (   rsbac_debug_adf[request] == LL_full
            || (   rsbac_debug_adf[request] == LL_denied
                && error) ) )
      do_log = TRUE;

    if(do_log)
      {
        char * request_name;
        char * target_type_name;
        char * new_target_type_name;
        char * target_id_name;
        char * new_target_id_name;
        char * attr_name;

        /* kmalloc all memory */
        request_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        target_type_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        new_target_type_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);
        #ifdef CONFIG_RSBAC_LOG_FULL_PATH
        target_id_name
         = kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN, GFP_KERNEL);
        new_target_id_name
         = kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + RSBAC_MAXNAMELEN, GFP_KERNEL);
           /* max. path name len + some extra */
        #else
        target_id_name = kmalloc(2 * RSBAC_MAXNAMELEN, GFP_KERNEL);
        new_target_id_name = kmalloc(2 * RSBAC_MAXNAMELEN, GFP_KERNEL);
           /* max. file name len + some extra */
        #endif
        attr_name = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);

        /* Getting basic information about this request */
        request_name[0] = (char) 0;
        target_type_name[0] = (char) 0;
        target_id_name[0] = (char) 0;
        new_target_type_name[0] = (char) 0;
        new_target_id_name[0] = (char) 0;
        attr_name[0] = (char) 0;
        get_request_name(request_name, request);
        get_target_name(target_type_name, target, target_id_name, tid);
        get_target_name(new_target_type_name, new_target,
                        new_target_id_name, new_tid);
        get_attribute_name(attr_name, attr);

#ifdef CONFIG_RSBAC_RMSG
        /* Logging without pseudo or user id, see previous request log */
        rsbac_printk(KERN_INFO
                 "rsbac_adf_set_attr(): request %s, caller_pid %u, target-type %s, tid %s, new_target-type %s, new_tid %s, attr %s, value %u, error %i\n",
                   request_name, (u_int) caller_pid, target_type_name, target_id_name,
                   new_target_type_name, new_target_id_name, attr_name, attr_val.dummy, error);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
        /* Logging without pseudo or user id, see previous request log */
        printk(KERN_INFO
               "rsbac_adf_set_attr(): request %s, caller_pid %u, target-type %s, tid %s, new_target-type %s, new_tid %s, attr %s, value %u, error %i\n",
               request_name, (u_int) caller_pid, target_type_name, target_id_name,
               new_target_type_name, new_target_id_name, attr_name, attr_val.dummy, error);
#endif
        /* kfree all helper mem */
        kfree(request_name);
        kfree(target_type_name);
        kfree(new_target_type_name);
        kfree(target_id_name);
        kfree(new_target_id_name);
        kfree(attr_name);
      }

/* count */
    rsbac_adf_set_attr_count[target]++;
#ifdef CONFIG_RSBAC_XSTATS
    rsbac_adf_set_attr_xcount[target][request]++;
#endif

    return(error);
  }; /* end of rsbac_adf_set_attr() */


/****************
 *
 * Secure Delete
 *
 ****************/

#ifdef CONFIG_RSBAC_SECDEL

/* open_by_dentry */
/* This is done by hand (copy from rsbac_read_open), because system calls */
/* are currently blocked by rsbac semaphores */

static int open_by_dentry(struct dentry * file_dentry_p, struct file * file_p)
  {
    int tmperr;

    if ( !(S_ISREG(file_dentry_p->d_inode->i_mode)) )
      { /* this is not a file! -> error! */
        printk(KERN_WARNING
               "open_by_dentry(): expected file is not a file!\n");
        return (-RSBAC_EWRITEFAILED);
      }
    /* Now we fill the file structure, and */
    /* if there is an open func, use it, otherwise ignore */
    if ((tmperr = init_private_file(file_p, file_dentry_p, O_WRONLY)))
      {
        printk(KERN_WARNING
               "open_by_dentry(): could not open file!\n");
        return (-RSBAC_EWRITEFAILED);
      }
    /* Without a write function we get into troubles -> error */
    if ((!file_p->f_op) || (!file_p->f_op->write))
      {
        printk(KERN_WARNING
               "open_by_dentry(): file write function missing!\n");
        if (file_p->f_op && file_p->f_op->release)
          file_p->f_op->release(file_dentry_p->d_inode,file_p);
        return(-RSBAC_EWRITEFAILED);
      }
    /* trying to get write access                                   */
    if (get_write_access(file_dentry_p->d_inode))
      {
        printk(KERN_WARNING
               "rsbac_write_open(): could not get write access!\n");
        if (file_p->f_op->release)
          file_p->f_op->release(file_dentry_p->d_inode,file_p);
        return(-RSBAC_EWRITEFAILED);
      }
    return 0;
  }

/*
 **********************
 * Secure File Truncation
 */

EXPORT_SYMBOL(rsbac_sec_trunc);
int rsbac_sec_trunc(struct dentry * dentry_p,
                    loff_t new_len, loff_t old_len)
  {
    boolean                       need_overwrite = FALSE;
    struct file                   file;
    int                           err = 0, tmperr = 0;
    int                           len;
    mm_segment_t                  oldfs;
    char                        * buffer;
#ifdef CONFIG_RSBAC_REG
    int i;
#endif

    /* security checks */
    if(   !dentry_p
       || !dentry_p->d_inode)
      return -RSBAC_EINVALIDPOINTER;
    if(!S_ISREG(dentry_p->d_inode->i_mode))
      return -RSBAC_EINVALIDTARGET;
    if(new_len >= old_len)
      return 0;
    buffer = kmalloc(RSBAC_SEC_DEL_CHUNK_SIZE, GFP_KERNEL);
    if(!buffer)
      return -RSBAC_ENOMEM;

    /******* MAC ********/
    #ifdef CONFIG_RSBAC_MAC
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_mac)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_mac(dentry_p);
    #endif  /* MAC */

    /******* FC ********/
    #ifdef CONFIG_RSBAC_FC
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_fc)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_fc(dentry_p);
    #endif  /* FC */

    /******* SIM ********/
    #ifdef CONFIG_RSBAC_SIM
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_sim)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_sim(dentry_p);
    #endif  /* SIM */

    /******* PM ********/
    #ifdef CONFIG_RSBAC_PM
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_pm)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_pm(dentry_p);
    #endif  /* PM */

    /******* MS ********/
    #ifdef CONFIG_RSBAC_MS
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_ms)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_ms(dentry_p);
    #endif  /* MS */

    /******* FF ********/
    #ifdef CONFIG_RSBAC_FF
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_ff)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_ff(dentry_p);
    #endif  /* FF */

    /******* RC ********/
    #ifdef CONFIG_RSBAC_RC
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_rc)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_rc(dentry_p);
    #endif  /* RC */

    /****** AUTH *******/
    #ifdef CONFIG_RSBAC_AUTH
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_auth)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_auth(dentry_p);
    #endif  /* AUTH */

    /****** REG *******/
    #ifdef CONFIG_RSBAC_REG
    for(i=0;i<RSBAC_REG_NR_ENTRIES;i++)
      {
        if(   rsbac_reg_entry[i].need_overwrite_func
        #ifdef CONFIG_RSBAC_SWITCH
           && rsbac_reg_entry[i].switch_on
        #endif
          )
          if(!need_overwrite)
            need_overwrite = rsbac_reg_entry[i].need_overwrite_func(dentry_p);
      }
    #endif  /* REG */

    /****** ACL *******/
    #ifdef CONFIG_RSBAC_ACL
    #ifdef CONFIG_RSBAC_SWITCH
    if (rsbac_switch_acl)
    #endif
      /* no need to call module, if already need_overwrite */
      if(!need_overwrite)
        need_overwrite = rsbac_need_overwrite_acl(dentry_p);
    #endif  /* ACL */

    if(need_overwrite)
      {
        printk(KERN_DEBUG
               "rsbac_sec_trunc(): zeroing of file %lu on device %u:%u from byte %lu to %lu!\n",
               dentry_p->d_inode->i_ino,
               MAJOR(dentry_p->d_inode->i_dev),
               MINOR(dentry_p->d_inode->i_dev),
               (u_long) new_len,
               (u_long) old_len-1);

        /* open */
        err = open_by_dentry(dentry_p, &file);
        if(err)
          return(err);

        /* OK, now we can start writing */

        /* Set current user space to kernel space, because write() reads
         * from user space
         */
        oldfs = get_fs();
        set_fs(KERNEL_DS);

        if(file.f_op->llseek)
          file.f_op->llseek(&file,new_len,0);
        else
          { /* taken from fs/read_write.c */
            file.f_pos = new_len;
            file.f_reada = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,14)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
            file.f_version = ++global_event;
#else
            file.f_version = ++event;
#endif
          }
        memset(buffer,0,RSBAC_SEC_DEL_CHUNK_SIZE);

        while(new_len < old_len)
          {
            len = min(RSBAC_SEC_DEL_CHUNK_SIZE, old_len-new_len);
            tmperr = file.f_op->write(&file,
                                     buffer,
                                     len,
                                     &file.f_pos);
            /* if none written, end of file is reached -> complain and return */
            if (tmperr < 0)
              {
                printk(KERN_WARNING
                       "rsbac_sec_trunc(): write error on file!\n");
                err = -RSBAC_EWRITEFAILED;
                goto out;
              }
            if(tmperr < len)
              {
                printk(KERN_WARNING
                       "rsbac_sec_trunc(): unexpectedly reached end of file!\n");
                goto out;
              }
            new_len += tmperr;
          }

        out:
        /* Set current user space back to user space, because read() writes */
        /* to user space */
        set_fs(oldfs);

        #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
        if (file.f_op->fsync)
          err = file.f_op->fsync(&file,dentry_p);
        #else
        if (file.f_op->fsync)
          err = file.f_op->fsync(&file,dentry_p,1);
        #endif
          
        if (file.f_op->flush)
          file.f_op->flush(&file);
        if (file.f_op->release)
          file.f_op->release(dentry_p->d_inode,&file);
        /* End of write access                     */
        put_write_access(dentry_p->d_inode);
      }

    /* Ready. */
    return(err);
  };

EXPORT_SYMBOL(rsbac_sec_del);
int rsbac_sec_del(struct dentry * dentry_p)
  {
    return(rsbac_sec_trunc(dentry_p,
                           0,
                           dentry_p->d_inode->i_size));
  };

#endif /* SECDEL */

/* end of rsbac/adf/main.c */
