/************************************ */
/* Rule Set Based Access Control      */
/*                                    */
/* Author and (c) 1999-2002:          */
/*   Amon Ott <ao@rsbac.org>          */
/*                                    */
/* Debug functions for all parts      */
/*                                    */
/* Last modified: 01/Mar/2002         */
/************************************ */
 
#include <asm/uaccess.h>
#include <rsbac/types.h>
#include <rsbac/aci.h>
#include <rsbac/aci_data_structures.h>
#include <rsbac/debug.h>
#include <rsbac/error.h>
#include <rsbac/proc_fs.h>
#include <rsbac/getname.h>
#include <rsbac/adf.h>
#include <rsbac/rkmem.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/console.h>

#ifdef CONFIG_RSBAC_DEBUG
/* Boolean debug switch for data structures */
int  rsbac_debug_ds = 0;

/* Boolean debug switch for writing of data structures */
int  rsbac_debug_write = 0;

/* Boolean debug switch for AEF */
EXPORT_SYMBOL(rsbac_debug_aef);
int  rsbac_debug_aef = 0;

/* Boolean debug switch for NO_WRITE (global) */
int  rsbac_debug_no_write = 0;

/* Boolean debug switch for stack debugging */
int  rsbac_debug_stack = 0;

/* Boolean debug switch for generic lists */
int  rsbac_debug_lists = 0;

#ifdef CONFIG_RSBAC_NET
int rsbac_debug_ds_net = 0;
int rsbac_debug_adf_net = 0;
int rsbac_debug_aef_net = 0;
#endif

#if defined(CONFIG_RSBAC_PM) || defined(CONFIG_RSBAC_PM_MAINT)
/* Boolean debug switch for PM data structures */
int  rsbac_debug_ds_pm = 0;
/* Boolean debug switch for PM syscalls / AEF */
int  rsbac_debug_aef_pm = 0;
/* Boolean debug switch for PM decisions / ADF */
int  rsbac_debug_adf_pm = 0;
#endif

#if defined(CONFIG_RSBAC_MS) || defined(CONFIG_RSBAC_MS_MAINT)
/* Boolean debug switch for MS decisions / ADF */
int  rsbac_debug_adf_ms = 0;
#endif

#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
/* Boolean debug switch for RC data structures */
int  rsbac_debug_ds_rc = 0;
/* Boolean debug switch for RC syscalls / AEF */
int  rsbac_debug_aef_rc = 0;
/* Boolean debug switch for RC decisions / ADF */
int  rsbac_debug_adf_rc = 0;
#endif

#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
/* Boolean debug switch for AUTH data structures */
int  rsbac_debug_ds_auth = 0;
/* Boolean debug switch for AUTH syscalls / AEF */
int  rsbac_debug_aef_auth = 0;
/* Boolean debug switch for AUTH decisions / ADF */
int  rsbac_debug_adf_auth = 0;
#endif

#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
/* Boolean debug switch for REG */
int  rsbac_debug_reg = 0;
#endif

#if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
/* Boolean debug switch for ACL data structures */
int  rsbac_debug_ds_acl = 0;
/* Boolean debug switch for ACL syscalls / AEF */
int  rsbac_debug_aef_acl = 0;
/* Boolean debug switch for ACL decisions / ADF */
int  rsbac_debug_adf_acl = 0;
#endif

#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)
  int  rsbac_debug_auto = 0;
#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */

#endif /* DEBUG */

#if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
/* Boolean switch for AUTH init: set may_setuid for /bin/login */
int  rsbac_auth_enable_login = 0;
#endif

/* Boolean switch for NO_WRITE (log levels only) */
boolean log_levels_no_write = FALSE;

/* Boolean switch whether list nr in data structures is allowed to be changed */
/* in read_fd_lists() */
int  rsbac_change_nr = 0;

#ifdef CONFIG_RSBAC_SOFTMODE
/* Boolean switch for RSBAC soft mode */
int  rsbac_softmode = 0;
#ifdef CONFIG_RSBAC_SOFTMODE_IND
int  rsbac_ind_softmode[SW_NONE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#endif

#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
EXPORT_SYMBOL(rsbac_in_softmode);
#endif
int rsbac_in_softmode(void)
  {
    return rsbac_softmode;
  }
#endif

#ifdef CONFIG_RSBAC_ALLOW_DAC_DISABLE_FULL
/* Boolean switch for disabling Linux DAC */
int  rsbac_dac_disable = 0;

#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
EXPORT_SYMBOL(rsbac_dac_is_disabled);
#endif
int rsbac_dac_is_disabled(void)
  {
    return rsbac_dac_disable;
  }
#endif

/* Boolean switch for no syslog option*/
#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG
int  rsbac_nosyslog = 0;
#endif

/* Array of Boolean debug switches for ADF */
int  rsbac_debug_adf_default = 1;
int  rsbac_debug_adf[R_NONE+1];

boolean rsbac_debug_adf_dirty = FALSE;

/* variables for rsbac_logging */
#if defined(CONFIG_RSBAC_RMSG)
#include <linux/poll.h>
#include <linux/smp.h>
#define RLOG_BUF_LEN (16384)
#define RLOG_BUF_MASK (RLOG_BUF_LEN-1)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
static struct wait_queue * rlog_wait = NULL;
#else
DECLARE_WAIT_QUEUE_HEAD(rlog_wait);
#endif
static char buf[1024];
static u_long rlog_size = 0;
static char rlog_buf[RLOG_BUF_LEN];
static unsigned long log_start = 0;
static unsigned long logged_chars = 0;
#endif

/* read_debug_adf_array() */
/* reading the system wide adf log level list from root filesystem */

static int read_debug_adf_array(void)
  {
    struct file                     file;
    int                             err = 0;
    int                             tmperr;
    enum rsbac_adf_request_t        request;
    mm_segment_t oldfs;
    u_int                           array_version;

        /* open file */
        if ((err = rsbac_read_open(RSBAC_DEBUG_ADF_NAME,
                                   &file,
                                   ROOT_DEV) ))
          return(err);

        /* OK, now we can start reading */
        /* There is a read function for this file, so read as many ACIs */
        /* as possible. A positive return value means a read success,   */
        /* 0 end of file and a negative value an error.                 */

        /* Set current user space to kernel space, because read() writes */
        /* to user space */
        oldfs = get_fs();
        set_fs(KERNEL_DS);

        tmperr = file.f_op->read(&file,
                                 (char *) &array_version,
                                 sizeof(array_version),
                                 &file.f_pos);
        /* error? */
	if (tmperr < sizeof(array_version))
	  {
            printk(KERN_WARNING
                   "read_debug_adf_array(): read error from file!\n");
            err = -RSBAC_EREADFAILED;
            goto end_read;
          }
        /* if wrong aci version, set no_write and skip */
        if (array_version > RSBAC_ADF_REQUEST_ARRAY_VERSION)
          {
            printk(KERN_WARNING
                   "read_debug_adf_array(): wrong array version %u, expected %u - skipping file and setting log_level_no_write!\n",
                   array_version, RSBAC_ADF_REQUEST_ARRAY_VERSION);
            log_levels_no_write = TRUE;
            err = -RSBAC_EREADFAILED;
            goto end_read;
	  }

        request = 0;
	do
	  {
	    tmperr = file.f_op->read(&file,
	                             (char *) &(rsbac_debug_adf[request]),
	                             sizeof(int),
	                             &file.f_pos);
	    request++;
	  }
	while ((tmperr > 0) && (request < R_NONE)); /* end of do */

	if (tmperr < 0)
	  {
            printk(KERN_WARNING "%s\n",
                    "read_debug_adf_array(): read error from file!");
            err = -RSBAC_EREADFAILED;
          }

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

        /* We do not need this file any more */
        rsbac_read_close(&file);
        return(err);
  }; /* end of read_debug_adf_array() */

#ifndef CONFIG_RSBAC_NO_WRITE
static int write_debug_adf_array(void)
  {
    struct file                     file;
    int                             err = 0;
    int                             tmperr;
    enum rsbac_adf_request_t        request;
    mm_segment_t oldfs;
    u_int                           array_version = RSBAC_ADF_REQUEST_ARRAY_VERSION;
    
    /* get rsbac write-to-disk semaphore */
    down(&rsbac_write_sem);

        /* open file */
        if ((err = rsbac_write_open(RSBAC_DEBUG_ADF_NAME,
                                    &file,
                                    ROOT_DEV) ))
          {
            up(&rsbac_write_sem);
            return(err);
          }

        /* OK, now we can start writing all user items. */
        /* A positive return value means a write success,   */
        /* 0 end of file and a negative value an error.                 */

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

        tmperr = file.f_op->write(&file,
                                  (char *) &array_version,
                                  sizeof(array_version),
                                  &file.f_pos);
#ifdef CONFIG_RSBAC_DEBUG
        if (rsbac_debug_write)
            printk(KERN_DEBUG "write_debug_adf_array(): wrote version\n");
#endif
        if (tmperr < sizeof(array_version))
          {
            printk(KERN_WARNING
                   "write_debug_adf_array(): write error %i on file!\n",
                   tmperr);
            err |= -RSBAC_EWRITEFAILED;
            goto end_write;
          }

        tmperr = 1;
        request = 0;
	while ((request < R_NONE) && (tmperr > 0))
	  {
	    tmperr = file.f_op->write(&file,
	                              (char *) &(rsbac_debug_adf[request]),
	                              sizeof(int),
	                              &file.f_pos);
            request++;
	  }
	if (tmperr <= 0)
	  {
            printk(KERN_WARNING "%s\n",
                    "write_debug_adf_array(): write error on file!");
            err = -RSBAC_EWRITEFAILED;
          }

end_write:
        /* Set current user space back to user space, because write() reads */
        /* from user space */
        set_fs(oldfs);

        /* End of write access                     */
        rsbac_write_close(&file);
        up(&rsbac_write_sem);
        return(err);
  }; /* end of write_debug_adf_array() */
#endif /* ifndef CONFIG_RSBAC_NO_WRITE */

void  rsbac_adf_log_switch(enum rsbac_adf_request_t request, enum rsbac_log_level_t value)
  {
    if(   (request >= 0)
       && (request < R_NONE)
       && (value >= LL_none)
       && (value <= LL_full))
      {
        rsbac_debug_adf[request] = value;
        rsbac_debug_adf_dirty = TRUE;
      }
  };

inline boolean rsbac_parse_koptions(char * line)
  {
    #if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    /* RSBAC: AUTH - set auth_may_setuid for /bin/login? */
    if (!strcmp(line,"rsbac_auth_enable_login"))
      {
        rsbac_auth_enable_login = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_SOFTMODE)
    /* RSBAC: softmode on? */
    if (!strcmp(line,"rsbac_softmode"))
      {
        rsbac_softmode = 1;
        return(TRUE);
      }
    #if defined(CONFIG_RSBAC_SOFTMODE_IND)
    /* RSBAC: softmode on for a module? */
    if (!strcmp(line,"rsbac_softmode_mac"))
      {
        rsbac_ind_softmode[MAC] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_fc"))
      {
        rsbac_ind_softmode[FC] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_sim"))
      {
        rsbac_ind_softmode[SIM] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_pm"))
      {
        rsbac_ind_softmode[PM] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_ms"))
      {
        rsbac_ind_softmode[MS] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_ff"))
      {
        rsbac_ind_softmode[FF] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_rc"))
      {
        rsbac_ind_softmode[RC] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_auth"))
      {
        rsbac_ind_softmode[AUTH] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_reg"))
      {
        rsbac_ind_softmode[REG] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_acl"))
      {
        rsbac_ind_softmode[ACL] = 1;
        return(TRUE);
      }
    if (!strcmp(line,"rsbac_softmode_cap"))
      {
        rsbac_ind_softmode[CAP] = 1;
        return(TRUE);
      }
    #endif
    #endif
    #ifdef CONFIG_RSBAC_ALLOW_DAC_DISABLE_FULL
    /* RSBAC: disable Linux DAC? */
    if (!strcmp(line,"rsbac_dac_disable"))
      {
        rsbac_dac_disable = 1;
        return(TRUE);
      }
    #endif
    #ifdef CONFIG_RSBAC_RMSG_NOSYSLOG
    if (!strcmp(line,"rsbac_nosyslog"))
      {
        rsbac_nosyslog = 1;
        return(TRUE);
      }
    #endif

#ifdef CONFIG_RSBAC_DEBUG
    #ifdef CONFIG_RSBAC_NET
    /* RSBAC: debug for all of net? */
    if (!strcmp(line,"rsbac_debug_net"))
      {
        rsbac_debug_ds_net = 1;
        rsbac_debug_aef_net = 1;
        rsbac_debug_adf_net = 1;
        return(TRUE);
      }
    /* RSBAC: debug for net data structures? */
    if (!strcmp(line,"rsbac_debug_ds_net"))
      {
        rsbac_debug_ds_net = 1;
        return(TRUE);
      }
    /* RSBAC: debug for net syscalls/AEF? */
    if (!strcmp(line,"rsbac_debug_aef_net"))
      {
        rsbac_debug_aef_net = 1;
        return(TRUE);
      }
    /* RSBAC: debug for net decisions/ADF? */
    if (!strcmp(line,"rsbac_debug_adf_net"))
      {
        rsbac_debug_adf_net = 1;
        return(TRUE);
      }
    #endif

    #if defined(CONFIG_RSBAC_PM) || defined(CONFIG_RSBAC_PM_MAINT)
    /* RSBAC: debug for all of pm? */
    if (!strcmp(line,"rsbac_debug_pm"))
      {
        rsbac_debug_ds_pm = 1;
        rsbac_debug_aef_pm = 1;
        rsbac_debug_adf_pm = 1;
        return(TRUE);
      }
    /* RSBAC: debug for pm data structures? */
    if (!strcmp(line,"rsbac_debug_ds_pm"))
      {
        rsbac_debug_ds_pm = 1;
        return(TRUE);
      }
    /* RSBAC: debug for PM-syscalls/AEF? */
    if (!strcmp(line,"rsbac_debug_aef_pm"))
      {
        rsbac_debug_aef_pm = 1;
        return(TRUE);
      }
    /* RSBAC: debug for PM-decisions/ADF? */
    if (!strcmp(line,"rsbac_debug_adf_pm"))
      {
        rsbac_debug_adf_pm = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_MS) || defined(CONFIG_RSBAC_MS_MAINT)
    /* RSBAC: debug for MS-decisions/ADF? */
    if (   !strcmp(line,"rsbac_debug_adf_ms")
        || !strcmp(line,"rsbac_debug_ms")
       )
      {
      	rsbac_debug_adf_ms = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
    /* RSBAC: debug for all of rc? */
    if (!strcmp(line,"rsbac_debug_rc"))
      {
        rsbac_debug_ds_rc = 1;
        rsbac_debug_aef_rc = 1;
        rsbac_debug_adf_rc = 1;
        return(TRUE);
      }
    /* RSBAC: debug for rc data structures? */
    if (!strcmp(line,"rsbac_debug_ds_rc"))
      {
        rsbac_debug_ds_rc = 1;
        return(TRUE);
      }
    /* RSBAC: debug for RC-syscalls/AEF? */
    if (!strcmp(line,"rsbac_debug_aef_rc"))
      {
        rsbac_debug_aef_rc = 1;
        return(TRUE);
      }
    /* RSBAC: debug for RC-decisions/ADF? */
    if (!strcmp(line,"rsbac_debug_adf_rc"))
      {
        rsbac_debug_adf_rc = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    /* RSBAC: debug for all of auth? */
    if (!strcmp(line,"rsbac_debug_auth"))
      {
        rsbac_debug_ds_auth = 1;
        rsbac_debug_aef_auth = 1;
        rsbac_debug_adf_auth = 1;
        return(TRUE);
      }
    /* RSBAC: debug for auth data structures? */
    if (!strcmp(line,"rsbac_debug_ds_auth"))
      {
        rsbac_debug_ds_auth = 1;
        return(TRUE);
      }
    /* RSBAC: debug for AUTH-syscalls/AEF? */
    if (!strcmp(line,"rsbac_debug_aef_auth"))
      {
        rsbac_debug_aef_auth = 1;
        return(TRUE);
      }
    /* RSBAC: debug for AUTH-decisions/ADF? */
    if (!strcmp(line,"rsbac_debug_adf_auth"))
      {
        rsbac_debug_adf_auth = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
    /* RSBAC: debug for all of reg? */
    if (!strcmp(line,"rsbac_debug_reg"))
      {
        rsbac_debug_reg = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
    /* RSBAC: debug for all of acl? */
    if (!strcmp(line,"rsbac_debug_acl"))
      {
        rsbac_debug_ds_acl = 1;
        rsbac_debug_aef_acl = 1;
        rsbac_debug_adf_acl = 1;
        return(TRUE);
      }
    /* RSBAC: debug for ACL data structures? */
    if (!strcmp(line,"rsbac_debug_ds_acl"))
      {
        rsbac_debug_ds_acl = 1;
        return(TRUE);
      }
    /* RSBAC: debug for ACL-syscalls/AEF? */
    if (!strcmp(line,"rsbac_debug_aef_acl"))
      {
        rsbac_debug_aef_acl = 1;
        return(TRUE);
      }
    /* RSBAC: debug for ACL-decisions/ADF? */
    if (!strcmp(line,"rsbac_debug_adf_acl"))
      {
        rsbac_debug_adf_acl = 1;
        return(TRUE);
      }
    #endif
    #if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)
    /* RSBAC: debug for auto-write? */
    if (!strcmp(line,"rsbac_debug_auto"))
      {
        rsbac_debug_auto = 1;
        return(TRUE);
      }
    #endif
    /* RSBAC: debug for all? */
    if (!strcmp(line,"rsbac_debug_all"))
      {
	rsbac_debug_ds = 1;
	rsbac_debug_write = 1;
	rsbac_debug_aef = 1;
	rsbac_debug_adf_default = 2;
        #if defined(CONFIG_RSBAC_PM) || defined(CONFIG_RSBAC_PM_MAINT)
	rsbac_debug_ds_pm = 1;
	rsbac_debug_aef_pm = 1;
	rsbac_debug_adf_pm = 1;
        #endif
        #if defined(CONFIG_RSBAC_MS) || defined(CONFIG_RSBAC_MS_MAINT)
	rsbac_debug_adf_ms = 1;
        #endif
        #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
	rsbac_debug_ds_rc = 1;
	rsbac_debug_aef_rc = 1;
	rsbac_debug_adf_rc = 1;
        #endif
        #if defined(CONFIG_RSBAC_AUTH)
	rsbac_debug_ds_auth = 1;
	rsbac_debug_aef_auth = 1;
	rsbac_debug_adf_auth = 1;
        #endif
        #if defined(CONFIG_RSBAC_ACL)
	rsbac_debug_ds_acl = 1;
	rsbac_debug_aef_acl = 1;
	rsbac_debug_adf_acl = 1;
        #endif
        #if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)
        rsbac_debug_auto = 1;
        #endif

	return(TRUE);
      }
    /* RSBAC: debug_lists */
    if (!strcmp(line,"rsbac_debug_lists"))
      {
        rsbac_debug_lists = 1;
        return(TRUE);
      }
    /* RSBAC: debug_stack */
    if (!strcmp(line,"rsbac_debug_stack"))
      {
        rsbac_debug_stack = 1;
        return(TRUE);
      }
    /* RSBAC: debug for data structures? */
    if (!strcmp(line,"rsbac_debug_ds"))
      {
        rsbac_debug_ds = 1;
        return(TRUE);
      }
    /* RSBAC: debug for writing of data structures? */
    if (!strcmp(line,"rsbac_debug_write"))
      {
        rsbac_debug_write = 1;
        return(TRUE);
      }
    /* RSBAC: debug for AEF? */
    if (!strcmp(line,"rsbac_debug_aef"))
      {
        rsbac_debug_aef = 1;
        return(TRUE);
      }
    /* RSBAC: debug_no_write for ds */
    if (!strcmp(line,"rsbac_debug_no_write"))
      {
        rsbac_debug_no_write = 1;
        return(TRUE);
      }
    /* RSBAC: debug default 0 for ADF */
    if (!strcmp(line,"rsbac_debug_no_adf"))
      {
        rsbac_debug_adf_default = 0;
        return(TRUE);
      }
    /* RSBAC: debug default 1 for ADF, log denied requests? (default value) */
    if (!strcmp(line,"rsbac_debug_adf"))
      {
        rsbac_debug_adf_default = 1;
        return(TRUE);
      }
    /* RSBAC: debug: log all for ADF, even GRANTED and DO_NOT_CARE? */
    if (!strcmp(line,"rsbac_debug_adf_all"))
      {
        rsbac_debug_adf_default = 2;
        return(TRUE);
      }
#endif /* DEBUG */

    /* nothing matched */
    return(FALSE);
  }

#if defined(CONFIG_RSBAC_RMSG)

static spinlock_t rsbac_log_lock;

/*
 * Commands to 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.
 */
int rsbac_log(int type, char * buf, int len)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
	unsigned long i, j, count, flags;
#else
	unsigned long i, j, limit, count;
#endif
	int do_clear = 0;
	char c;
	int error = -EPERM;

        union rsbac_target_id_t       rsbac_target_id;
        union rsbac_attribute_value_t rsbac_attribute_value;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
        lock_kernel();
#endif

        /* RSBAC */
#ifdef CONFIG_RSBAC_DEBUG
        if (rsbac_debug_aef)
          printk(KERN_DEBUG "rsbac_log(): calling ADF\n");
#endif
        rsbac_target_id.scd = ST_rsbaclog;
        rsbac_attribute_value.dummy = 0;
        if ((type == 2) || (type == 3))
          {
            if (!rsbac_adf_request(R_GET_STATUS_DATA,
                                   current->pid,
                                   T_SCD,
                                   rsbac_target_id,
                                   A_none,
                                   rsbac_attribute_value))
              {
                error = -EPERM;
                goto out;
              }
          }
        else
          {
            if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA,
                                   current->pid,
                                   T_SCD,
                                   rsbac_target_id,
                                   A_none,
                                   rsbac_attribute_value))
              {
                error = -EPERM;
                goto out;
              }
          }

	error = 0;
	switch (type) {
	case 0:		/* Close log */
		break;
	case 1:		/* Open log */
		break;
	case 2:		/* Read from log */
		error = -EINVAL;
		if (!buf || len < 0)
			goto out;
		error = 0;
		if (!len)
			goto out;
		error = verify_area(VERIFY_WRITE,buf,len);
		if (error)
			goto out;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
		cli();
		error = -ERESTARTSYS;
		while (!rlog_size) {
			if (signal_pending(current)) {
				sti();
				goto out;
			}
			interruptible_sleep_on(&rlog_wait);
		}
		i = 0;
		while (rlog_size && i < len) {
			c = *((char *) rlog_buf+log_start);
			log_start++;
			rlog_size--;
			log_start &= RLOG_BUF_MASK;
			sti();
			__put_user(c,buf);
			buf++;
			i++;
			cli();
		}
		sti();
#else
		error = wait_event_interruptible(rlog_wait, rlog_size);
		if(error)
		  goto out;
		i = 0;
		spin_lock_irq(&rsbac_log_lock);
		while (rlog_size && i < len) {
			c = rlog_buf[log_start & RLOG_BUF_MASK];
			log_start++;
			rlog_size--;
			spin_unlock_irq(&rsbac_log_lock);
			__put_user(c,buf);
			buf++;
			i++;
			spin_lock_irq(&rsbac_log_lock);
		}
		spin_unlock_irq(&rsbac_log_lock);
#endif
		error = i;
		break;
	case 4:		/* Read/clear last kernel messages */
		do_clear = 1; 
		/* FALL THRU */
	case 3:		/* Read last kernel messages */
		error = -EINVAL;
		if (!buf || len < 0)
			goto out;
		error = 0;
		if (!len)
			goto out;
		error = verify_area(VERIFY_WRITE,buf,len);
		if (error)
			goto out;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
		/*
		 * The logged_chars, log_start, and rlog_size values may
		 * change from an interrupt, so we disable interrupts.
		 */
		__save_flags(flags);
		__cli();
		count = len;
		if (count > RLOG_BUF_LEN)
			count = RLOG_BUF_LEN;
		if (count > logged_chars)
			count = logged_chars;
		j = log_start + rlog_size - count;
		__restore_flags(flags);
		for (i = 0; i < count; i++) {
			c = *((char *) rlog_buf+(j++ & RLOG_BUF_MASK));
			__put_user(c, buf++);
		}
		if (do_clear)
			logged_chars = 0;
		error = i;
#else
		count = len;
		if (count > RLOG_BUF_LEN)
			count = RLOG_BUF_LEN;
		if (count > logged_chars)
			count = logged_chars;
		if (do_clear)
			logged_chars = 0;
		limit = log_start + rlog_size;
		/*
		 * __put_user() could sleep, and while we sleep
		 * printk() could overwrite the messages 
		 * we try to copy to user space. Therefore
		 * the messages are copied in reverse. <manfreds>
		 */
		for(i=0;i < count;i++) {
			j = limit-1-i;
			if (j+RLOG_BUF_LEN < log_start+rlog_size)
				break;
			c = rlog_buf[ j  & RLOG_BUF_MASK ];
			__put_user(c,&buf[count-1-i]);
		}
		error = i;
		if(i != count) {
			int offset = count-error;
			/* buffer overflow during copy, correct user buffer. */
			for(i=0;i<error;i++) {
				__get_user(c,&buf[i+offset]);
				__put_user(c,&buf[i]);
			}
		}
#endif
		break;
	case 5:		/* Clear ring buffer */
		logged_chars = 0;
		break;
	default:
		error = -EINVAL;
		break;
	}
out:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
        unlock_kernel();
#endif
	return error;
}

#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
EXPORT_SYMBOL(rsbac_printk);
#endif
int rsbac_printk(const char *fmt, ...)
{
	va_list args;
	int i;
	char *msg, *p, *buf_end;
	int line_feed;
	static signed char msg_level = -1;
	long flags;

	spin_lock_irqsave(&rsbac_log_lock, flags);
	va_start(args, fmt);
	i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
	buf_end = buf + 3 + i;
	va_end(args);
	for (p = buf + 3; p < buf_end; p++) {
		msg = p;
		if (msg_level < 0) {
			if (
				p[0] != '<' ||
				p[1] < '0' || 
				p[1] > '7' ||
				p[2] != '>'
			) {
				p -= 3;
				p[0] = '<';
				p[1] = RSBAC_DEF_MESS_LOGLEVEL + '0';
				p[2] = '>';
			} else
				msg += 3;
			msg_level = p[1] - '0';
		}
		line_feed = 0;
		for (; p < buf_end; p++) {
			rlog_buf[(log_start+rlog_size) & (RLOG_BUF_LEN-1)] = *p;
			if (rlog_size < RLOG_BUF_LEN)
				rlog_size++;
			else {
				log_start++;
				log_start &= RLOG_BUF_LEN-1;
			}
			logged_chars++;
			if (*p == '\n') {
				line_feed = 1;
				break;
			}
		}
		if (line_feed)
			msg_level = -1;
	}
	spin_unlock_irqrestore(&rsbac_log_lock, flags);
	wake_up_interruptible(&rlog_wait);
	return i;
}

#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
static int rmsg_open(struct inode * inode, struct file * file)
{
	return rsbac_log(1,NULL,0);
}

static int rmsg_release(struct inode * inode, struct file * file)
{
	(void) rsbac_log(0,NULL,0);
	return 0;
}

static ssize_t rmsg_read(struct file * file, char * buf,
			 size_t count, loff_t *ppos)
{
	return rsbac_log(2,buf,count);
}

static unsigned int rmsg_poll(struct file *file, poll_table * wait)
{
	poll_wait(file, &rlog_wait, wait);
	if (rlog_size)
		return POLLIN | POLLRDNORM;
	return 0;
}

static struct file_operations proc_rmsg_operations = {
      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        NULL,           /* owner */
      #endif
	NULL,		/* rmsg_lseek */
	rmsg_read,
	NULL,		/* rmsg_write */
	NULL,		/* rmsg_readdir */
	rmsg_poll,	/* rmsg_poll */
	NULL,		/* rmsg_ioctl */
	NULL,		/* mmap */
	rmsg_open,
	NULL,		/* flush */
	rmsg_release,
	NULL		/* can't fsync */
};

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
static struct inode_operations proc_rmsg_inode_operations = {
	&proc_rmsg_operations,	/* default base directory file-ops */
	NULL,			/* create */
	NULL,			/* lookup */
	NULL,			/* link */
	NULL,			/* unlink */
	NULL,			/* symlink */
	NULL,			/* mkdir */
	NULL,			/* rmdir */
	NULL,			/* mknod */
	NULL,			/* rename */
	NULL,			/* readlink */
	NULL,			/* follow_link */
	NULL,			/* readpage */
	NULL,			/* writepage */
	NULL,			/* bmap */
	NULL,			/* truncate */
	NULL			/* permission */
};
#endif /* VERSION < 2.3.48 */
#endif /* PROC */
#endif /* RMSG */

#if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
#ifndef PROC_BLOCK_SIZE
#define PROC_BLOCK_SIZE	(3*1024)  /* 4K page size but our output routines use some slack for overruns */
#endif

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

  union rsbac_target_id_t       rsbac_target_id;
  union rsbac_attribute_value_t rsbac_attribute_value;

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

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

  name = rsbac_kmalloc(RSBAC_MAXNAMELEN);
  if(!name)
    return -ENOMEM;
  name2 = rsbac_kmalloc(RSBAC_MAXNAMELEN);
  if(!name2)
    {
      rsbac_kfree(name);
      return -ENOMEM;
    }
    
  len += sprintf(buffer, "RSBAC Log Levels\n----------------\n");
  if(rsbac_debug_adf_dirty)
    {
      len += sprintf(buffer + len, "(list is dirty)\n");
      pos = begin + len;
      if (pos < offset)
        {
          len = 0;
          begin = pos;
        }
      if (pos > offset+length)
        goto out;
    }

  for (i = 0; i<R_NONE; i++)
    {
      len += sprintf(buffer + len, "%-23s\t%i/%s\n",
                     get_request_name(name, i),
                     rsbac_debug_adf[i],
                     get_log_level_name(name2, rsbac_debug_adf[i]) );
      pos = begin + len;
      if (pos < offset)
        {
          len = 0;
          begin = pos;
        }
      if (pos > offset+length)
        break;
    }

out:
  *start = buffer + (offset - begin);
  len -= (offset - begin);
  
  if (len > length)
    len = length;
  rsbac_kfree(name);
  rsbac_kfree(name2);

  return len;
}

static ssize_t log_levels_proc_write(struct file * file, const char * buf,
                                     u_long count, void *ppos)
{
    ssize_t err = -EINVAL;
    char * k_buf;
    char * p;
    unsigned int log_level;
    char rname[RSBAC_MAXNAMELEN];
    int i;

    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if(count > PROC_BLOCK_SIZE) {
	return(-EOVERFLOW);
    }

    if (!(k_buf = (char *) __get_free_page(GFP_KERNEL)))
      return(-ENOMEM);
    copy_from_user(k_buf, buf, count);

  if(count < 15 || strncmp("log_levels", k_buf, 10))
    {
      goto out;
    }
  if (!rsbac_is_initialized())
    {
      err=-ENOSYS;
      goto out;
    }

    /*
     * Usage: echo "log_levels request #N" > /proc/rsbac_info/log_levels
     *   to set log level for request to given value
     */
    for(i=0; i<R_NONE; i++)
      {
        get_request_name(rname,i);
        if(!strncmp(rname, k_buf + 11, strlen(rname))) 
          {
#ifdef CONFIG_RSBAC_DEBUG
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "log_levels_proc_write(): calling ADF\n");
#endif
            rsbac_target_id.dummy = 0;
            rsbac_attribute_value.request = i;
            if (!rsbac_adf_request(R_SWITCH_LOG,
                                   current->pid,
                                   T_NONE,
                                   rsbac_target_id,
                                   A_request,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
                goto out;
              }
	    p = k_buf + 11 + strlen(rname)+1;

            if( *p == '\0' )
              goto out;

            log_level = simple_strtoul(p, NULL, 0);
            /* only accept 0 or 1 */
            if(   (log_level == LL_none)
               || (log_level == LL_denied)
               || (log_level == LL_full)
              )
              {
                printk(KERN_INFO
                       "log_levels_proc_write(): setting %s log level to %u\n",
                       rname, log_level);
                rsbac_debug_adf[i] = log_level;
                err = count;
                goto out;
              }
            else
              {
                printk(KERN_INFO
                       "log_levels_proc_write(): rejecting invalid log level (should be %u, %u or %u)\n",
                       LL_none, LL_denied, LL_full);
                goto out;
              }
          }
      }

out:
  free_page((ulong) k_buf);
  return(err);
  }


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

  union rsbac_target_id_t       rsbac_target_id;
  union rsbac_attribute_value_t rsbac_attribute_value;

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

#ifdef CONFIG_RSBAC_DEBUG
  if (rsbac_debug_aef) printk(KERN_DEBUG "debug_proc_info(): calling ADF\n");
#endif
  rsbac_target_id.scd = ST_rsbac;
  rsbac_attribute_value.dummy = 0;
  if (!rsbac_adf_request(R_GET_STATUS_DATA,
                         current->pid,
                         T_SCD,
                         rsbac_target_id,
                         A_none,
                         rsbac_attribute_value))
    {
      return -EPERM;
    }
  len += sprintf(buffer, "RSBAC Debug Settings\n--------------------\n");

#ifdef CONFIG_RSBAC_SOFTMODE
  len += sprintf(buffer + len, "rsbac_softmode is %i\n",
                 rsbac_softmode);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#ifdef CONFIG_RSBAC_SOFTMODE_IND
#ifdef CONFIG_RSBAC_MAC
  len += sprintf(buffer + len, "rsbac_ind_softmode[MAC] is %i\n",
                 rsbac_ind_softmode[MAC]);
#endif
#ifdef CONFIG_RSBAC_FC
  len += sprintf(buffer + len, "rsbac_ind_softmode[FC] is %i\n",
                 rsbac_ind_softmode[FC]);
#endif
#ifdef CONFIG_RSBAC_SIM
  len += sprintf(buffer + len, "rsbac_ind_softmode[SIM] is %i\n",
                 rsbac_ind_softmode[SIM]);
#endif
#ifdef CONFIG_RSBAC_PM
  len += sprintf(buffer + len, "rsbac_ind_softmode[PM] is %i\n",
                 rsbac_ind_softmode[PM]);
#endif
#ifdef CONFIG_RSBAC_MS
  len += sprintf(buffer + len, "rsbac_ind_softmode[MS] is %i\n",
                 rsbac_ind_softmode[MS]);
#endif
#ifdef CONFIG_RSBAC_FF
  len += sprintf(buffer + len, "rsbac_ind_softmode[FF] is %i\n",
                 rsbac_ind_softmode[FF]);
#endif
#ifdef CONFIG_RSBAC_RC
  len += sprintf(buffer + len, "rsbac_ind_softmode[RC] is %i\n",
                 rsbac_ind_softmode[RC]);
#endif
#ifdef CONFIG_RSBAC_AUTH
  len += sprintf(buffer + len, "rsbac_ind_softmode[AUTH] is %i\n",
                 rsbac_ind_softmode[AUTH]);
#endif
#ifdef CONFIG_RSBAC_REG
  len += sprintf(buffer + len, "rsbac_ind_softmode[REG] is %i\n",
                 rsbac_ind_softmode[REG]);
#endif
#ifdef CONFIG_RSBAC_ACL
  len += sprintf(buffer + len, "rsbac_ind_softmode[ACL] is %i\n",
                 rsbac_ind_softmode[ACL]);
#endif
#ifdef CONFIG_RSBAC_CAP
  len += sprintf(buffer + len, "rsbac_ind_softmode[CAP] is %i\n",
                 rsbac_ind_softmode[CAP]);
#endif
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

#endif
#endif

#ifdef CONFIG_RSBAC_ALLOW_DAC_DISABLE_FULL
  len += sprintf(buffer + len, "rsbac_dac_disable is %i\n",
                 rsbac_dac_disable);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG
  len += sprintf(buffer + len, "rsbac_nosyslog is %i\n",
                 rsbac_nosyslog);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_AUTH)
  len += sprintf(buffer + len, "rsbac_auth_enable_login is %i\n",
                 rsbac_auth_enable_login);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#ifdef CONFIG_RSBAC_DEBUG
  len += sprintf(buffer + len, "rsbac_debug_write is %i\n",
                 rsbac_debug_write);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

  len += sprintf(buffer + len, "rsbac_debug_stack is %i\n",
                 rsbac_debug_stack);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

  len += sprintf(buffer + len, "rsbac_debug_lists is %i\n",
                 rsbac_debug_lists);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

  len += sprintf(buffer + len, "rsbac_debug_ds is %i\n",
                 rsbac_debug_ds);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

  len += sprintf(buffer + len, "rsbac_debug_aef is %i\n",
                 rsbac_debug_aef);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

  len += sprintf(buffer + len, "rsbac_debug_no_write is %i\n",
                 rsbac_debug_no_write);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
/* Boolean debug switch for REG */
  len += sprintf(buffer + len, "rsbac_debug_reg is %i\n",
                 rsbac_debug_reg);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_NET)
/* Boolean debug switch for NET data structures */
  len += sprintf(buffer + len, "rsbac_debug_ds_net is %i\n",
                 rsbac_debug_ds_net);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for NET syscalls / AEF */
  len += sprintf(buffer + len, "rsbac_debug_aef_net is %i\n",
                 rsbac_debug_aef_net);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for NET decisions / ADF */
  len += sprintf(buffer + len, "rsbac_debug_adf_net is %i\n",
                 rsbac_debug_adf_net);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_PM) || defined(CONFIG_RSBAC_PM_MAINT)
/* Boolean debug switch for PM data structures */
  len += sprintf(buffer + len, "rsbac_debug_ds_pm is %i\n",
                 rsbac_debug_ds_pm);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for PM syscalls / AEF */
  len += sprintf(buffer + len, "rsbac_debug_aef_pm is %i\n",
                 rsbac_debug_aef_pm);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for PM decisions / ADF */
  len += sprintf(buffer + len, "rsbac_debug_adf_pm is %i\n",
                 rsbac_debug_adf_pm);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_MS) || defined(CONFIG_RSBAC_MS_MAINT)
/* Boolean debug switch for MS decisions / ADF */
  len += sprintf(buffer + len, "rsbac_debug_adf_ms is %i\n",
                 rsbac_debug_adf_ms);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
/* Boolean debug switch for RC data structures */
  len += sprintf(buffer + len, "rsbac_debug_ds_rc is %i\n",
                 rsbac_debug_ds_rc);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for RC syscalls / AEF */
  len += sprintf(buffer + len, "rsbac_debug_aef_rc is %i\n",
                 rsbac_debug_aef_rc);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for RC decisions / ADF */
  len += sprintf(buffer + len, "rsbac_debug_adf_rc is %i\n",
                 rsbac_debug_adf_rc);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_AUTH)
/* Boolean debug switch for AUTH data structures */
  len += sprintf(buffer + len, "rsbac_debug_ds_auth is %i\n",
                 rsbac_debug_ds_auth);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for AUTH syscalls / AEF */
  len += sprintf(buffer + len, "rsbac_debug_aef_auth is %i\n",
                 rsbac_debug_aef_auth);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for AUTH decisions / ADF */
  len += sprintf(buffer + len, "rsbac_debug_adf_auth is %i\n",
                 rsbac_debug_adf_auth);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_ACL)
/* Boolean debug switch for ACL data structures */
  len += sprintf(buffer + len, "rsbac_debug_ds_acl is %i\n",
                 rsbac_debug_ds_acl);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for ACL syscalls / AEF */
  len += sprintf(buffer + len, "rsbac_debug_aef_acl is %i\n",
                 rsbac_debug_aef_acl);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

/* Boolean debug switch for ACL decisions / ADF */
  len += sprintf(buffer + len, "rsbac_debug_adf_acl is %i\n",
                 rsbac_debug_adf_acl);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif

#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)
  len += sprintf(buffer + len, "rsbac_debug_auto is %i\n",
                 rsbac_debug_auto);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;
#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */
#endif /* DEBUG */

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

static ssize_t debug_proc_write(struct file * file, const char * buf,
                                u_long count, void *ppos)
{
    ssize_t err = -EINVAL;
    char * k_buf;
    char * p;
    unsigned int debug_level;
#ifdef CONFIG_RSBAC_SOFTMODE_IND
    enum rsbac_switch_target_t sw_target;
#endif

    union rsbac_target_id_t       rsbac_target_id;
    union rsbac_attribute_value_t rsbac_attribute_value;

    if(count > PROC_BLOCK_SIZE) {
	return(-EOVERFLOW);
    }

    if (!(k_buf = (char *) __get_free_page(GFP_KERNEL)))
      return(-ENOMEM);
    copy_from_user(k_buf, buf, count);

  if(count < 10)
    goto out;
  if(!strncmp("debug", k_buf, 5))
    {
      p = k_buf + 6;
    }
  else
  if(!strncmp("rsbac_debug", k_buf, 11))
    {
      p = k_buf + 12;
    }
  else
    goto out;

  if (!rsbac_is_initialized())
    {
      err=-ENOSYS;
      goto out;
    }


#ifdef CONFIG_RSBAC_SOFTMODE
#ifdef CONFIG_RSBAC_SOFTMODE_IND
/* Boolean switch for RSBAC individual soft mode */
    /*
     * Usage: echo "debug ind_softmode modname #N" > /proc/rsbac_info/debug
     *   to set rsbac_ind_softmode[module] to given value
     */
    if(!strncmp("ind_softmode", k_buf + 6, 12)) 
      {
        char tmp[20];

	p += 13;

        if( *p == '\0' )
          goto out;

        sw_target = get_switch_target_nr(p);
        if(sw_target == SW_NONE)
          goto out;
        get_switch_target_name(tmp, sw_target);
        p += strlen(tmp)+1;
        if( *p == '\0' )
          goto out;
        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
#if defined(CONFIG_RSBAC_DEBUG)
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "debug_proc_write(): calling ADF for switching\n");
#endif
            rsbac_target_id.dummy = 0;
            rsbac_attribute_value.switch_target = sw_target;
            if (!rsbac_adf_request(R_SWITCH_MODULE,
                                   current->pid,
                                   T_NONE,
                                   rsbac_target_id,
                                   A_switch_target,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
                goto out;
              }
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_ind_softmode[%s] to %u\n",
                   tmp,
                   debug_level);
            rsbac_ind_softmode[sw_target] = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid ind_softmode value (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

/* Boolean switch for RSBAC soft mode */
    /*
     * Usage: echo "debug softmode #N" > /proc/rsbac_info/debug
     *   to set rsbac_softmode to given value
     */
    if(!strncmp("softmode", k_buf + 6, 8)) 
      {
	p += 9;

        if( *p == '\0' )
          goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
#if defined(CONFIG_RSBAC_DEBUG)
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "debug_proc_write(): calling ADF for softmode\n");
#endif
            rsbac_target_id.dummy = 0;
            rsbac_attribute_value.switch_target = SOFTMODE;
            if (!rsbac_adf_request(R_SWITCH_MODULE,
                                   current->pid,
                                   T_NONE,
                                   rsbac_target_id,
                                   A_switch_target,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
                goto out;
              }
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_softmode to %u\n",
                   debug_level);
            rsbac_softmode = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid softmode value (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#ifdef CONFIG_RSBAC_ALLOW_DAC_DISABLE_FULL
/* Boolean switch for disabling Linux DAC */
    /*
     * Usage: echo "debug dac_disable #N" > /proc/rsbac_info/debug
     *   to set rsbac_softmode to given value
     */
    if(!strncmp("dac_disable", k_buf + 6, 11)) 
      {
	p += 12;

        if( *p == '\0' )
          goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
#if defined(CONFIG_RSBAC_DEBUG)
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "debug_proc_write(): calling ADF for dac_disable\n");
#endif
            rsbac_target_id.dummy = 0;
            rsbac_attribute_value.dummy = 0;
            if (!rsbac_adf_request(R_MODIFY_PERMISSIONS_DATA,
                                   current->pid,
                                   T_NONE,
                                   rsbac_target_id,
                                   A_none,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
                goto out;
              }
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_dac_disable to %u\n",
                   debug_level);
            rsbac_dac_disable = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid dac_disabled value (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#ifdef CONFIG_RSBAC_RMSG_NOSYSLOG
/* Boolean switch for disabling logging to syslog */
    /*
     * Usage: echo "debug nosyslog #N" > /proc/rsbac_info/debug
     *   to set rsbac_nosyslog to given value
     */
    if(!strncmp("nosyslog", k_buf + 6, 8)) 
      {
	p += 9;

        if( *p == '\0' )
          goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
#if defined(CONFIG_RSBAC_DEBUG)
            if (rsbac_debug_aef)
              printk(KERN_DEBUG "debug_proc_write(): calling ADF for nosyslog\n");
#endif
            rsbac_target_id.dummy = 0;
            rsbac_attribute_value.dummy = 0;
            if (!rsbac_adf_request(R_SWITCH_LOG,
                                   current->pid,
                                   T_NONE,
                                   rsbac_target_id,
                                   A_none,
                                   rsbac_attribute_value))
              {
                err = -EPERM;
                goto out;
              }
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_nosyslog to %u\n",
                   debug_level);
            rsbac_nosyslog = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid nosyslog value (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_DEBUG)
    if (rsbac_debug_aef) printk(KERN_DEBUG "debug_proc_write(): calling ADF\n");
    rsbac_target_id.scd = ST_rsbac;
    rsbac_attribute_value.dummy = 0;
    if (!rsbac_adf_request(R_MODIFY_SYSTEM_DATA,
                           current->pid,
                           T_SCD,
                           rsbac_target_id,
                           A_none,
                           rsbac_attribute_value))
      {
        err = -EPERM;
        goto out;
      }

#if defined(CONFIG_RSBAC_NET)
/* Boolean debug switch for NET data structures */
    /*
     * Usage: echo "debug ds_net #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_ds_net to given value
     */
    if(!strncmp("ds_net", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
          goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_ds_net to %u\n",
                   debug_level);
            rsbac_debug_ds_net = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
/* Boolean debug switch for NET syscalls / AEF */
    /*
     * Usage: echo "debug aef_net #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_aef_net to given value
     */
    if(!strncmp("aef_net", k_buf + 6, 7)) 
      {
	p += 8;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_aef_net to %u\n",
                   debug_level);
            rsbac_debug_aef_net = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

/* Boolean debug switch for NET decisions / ADF */
    /*
     * Usage: echo "debug adf_net #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_adf_net to given value
     */
    if(!strncmp("adf_net", k_buf + 6, 7)) 
      {
	p += 8;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_adf_net to %u\n",
                   debug_level);
            rsbac_debug_adf_net = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_PM) || defined(CONFIG_RSBAC_PM_MAINT)
/* Boolean debug switch for PM data structures */
    /*
     * Usage: echo "debug ds_pm #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_ds_pm to given value
     */
    if(!strncmp("ds_pm", k_buf + 6, 5)) 
      {
	p += 6;

        if( *p == '\0' )
          goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_ds_pm to %u\n",
                   debug_level);
            rsbac_debug_ds_pm = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
/* Boolean debug switch for PM syscalls / AEF */
    /*
     * Usage: echo "debug aef_pm #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_aef_pm to given value
     */
    if(!strncmp("aef_pm", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_aef_pm to %u\n",
                   debug_level);
            rsbac_debug_aef_pm = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

/* Boolean debug switch for PM decisions / ADF */
    /*
     * Usage: echo "debug adf_pm #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_adf_pm to given value
     */
    if(!strncmp("adf_pm", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_adf_pm to %u\n",
                   debug_level);
            rsbac_debug_adf_pm = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_MS) || defined(CONFIG_RSBAC_MS_MAINT)
/* Boolean debug switch for PM decisions / ADF */
    /*
     * Usage: echo "debug adf_ms #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_adf_ms to given value
     */
    if(!strncmp("adf_ms", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_adf_ms to %u\n",
                   debug_level);
            rsbac_debug_adf_ms = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
/* Boolean debug switch for RC data structures */
    /*
     * Usage: echo "debug ds_rc #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_ds_rc to given value
     */
    if(!strncmp("ds_rc", k_buf + 6, 5)) 
      {
	p += 6;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_ds_rc to %u\n",
                   debug_level);
            rsbac_debug_ds_rc = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
/* Boolean debug switch for RC syscalls / AEF */
    /*
     * Usage: echo "debug aef_rc #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_aef_rc to given value
     */
    if(!strncmp("aef_rc", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_aef_rc to %u\n",
                   debug_level);
            rsbac_debug_aef_rc = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

/* Boolean debug switch for RC decisions / ADF */
    /*
     * Usage: echo "debug adf_rc #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_adf_rc to given value
     */
    if(!strncmp("adf_rc", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_adf_rc to %u\n",
                   debug_level);
            rsbac_debug_adf_rc = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_AUTH)
/* Boolean debug switch for AUTH data structures */
    /*
     * Usage: echo "debug ds_auth #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_ds_auth to given value
     */
    if(!strncmp("ds_auth", k_buf + 6, 7)) 
      {
	p += 8;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_ds_auth to %u\n",
                   debug_level);
            rsbac_debug_ds_auth = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
/* Boolean debug switch for AUTH syscalls / AEF */
    /*
     * Usage: echo "debug aef_auth #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_aef_auth to given value
     */
    if(!strncmp("aef_auth", k_buf + 6, 8)) 
      {
	p += 9;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_aef_auth to %u\n",
                   debug_level);
            rsbac_debug_aef_auth = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

/* Boolean debug switch for AUTH decisions / ADF */
    /*
     * Usage: echo "debug adf_auth #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_adf_auth to given value
     */
    if(!strncmp("adf_auth", k_buf + 6, 8)) 
      {
	p += 9;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_adf_auth to %u\n",
                   debug_level);
            rsbac_debug_adf_auth = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
/* Boolean debug switch for REG */
    /*
     * Usage: echo "debug reg #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_reg to given value
     */
    if(!strncmp("reg", k_buf + 6, 3)) 
      {
	p += 3;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_reg to %u\n",
                   debug_level);
            rsbac_debug_reg = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

#if defined(CONFIG_RSBAC_ACL)
/* Boolean debug switch for ACL data structures */
    /*
     * Usage: echo "debug ds_acl #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_ds_acl to given value
     */
    if(!strncmp("ds_acl", k_buf + 6, 6)) 
      {
	p += 7;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_ds_acl to %u\n",
                   debug_level);
            rsbac_debug_ds_acl = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
/* Boolean debug switch for ACL syscalls / AEF */
    /*
     * Usage: echo "debug aef_acl #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_aef_acl to given value
     */
    if(!strncmp("aef_acl", k_buf + 6, 7)) 
      {
	p += 8;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_aef_acl to %u\n",
                   debug_level);
            rsbac_debug_aef_acl = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

/* Boolean debug switch for ACL decisions / ADF */
    /*
     * Usage: echo "debug adf_acl #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_adf_acl to given value
     */
    if(!strncmp("adf_acl", k_buf + 6, 7)) 
      {
	p += 8;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_adf_acl to %u\n",
                   debug_level);
            rsbac_debug_adf_acl = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif

    /*
     * Usage: echo "debug ds #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_ds to given value
     */
    if(!strncmp("ds", k_buf + 6, 2)) 
      {
	p += 3;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_ds to %u\n",
                   debug_level);
            rsbac_debug_ds = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

    /*
     * Usage: echo "debug write #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_write to given value
     */
    if(!strncmp("write", k_buf + 6, 5)) 
      {
	p += 6;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_write to %u\n",
                   debug_level);
            rsbac_debug_write = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

    /*
     * Usage: echo "debug stack #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_stack to given value
     */
    if(!strncmp("stack", k_buf + 6, 5)) 
      {
	p += 6;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_stack to %u\n",
                   debug_level);
            rsbac_debug_stack = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

    /*
     * Usage: echo "debug lists #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_lists to given value
     */
    if(!strncmp("lists", k_buf + 6, 5)) 
      {
	p += 6;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_lists to %u\n",
                   debug_level);
            rsbac_debug_lists = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

    /* Boolean debug switch for AEF */
    /*
     * Usage: echo "debug aef #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_aef to given value
     */
    if(!strncmp("aef", k_buf + 6, 3)) 
      {
	p += 4;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_aef to %u\n",
                   debug_level);
            rsbac_debug_aef = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

/* Boolean debug switch for NO_WRITE */
    /*
     * Usage: echo "debug no_write #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_no_write to given value
     */
    if(!strncmp("no_write", k_buf + 6, 8)) 
      {
	p += 9;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_no_write to %u\n",
                   debug_level);
            rsbac_debug_no_write = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }

#if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)
    /*
     * Usage: echo "debug auto #N" > /proc/rsbac_info/debug
     *   to set rsbac_debug_auto to given value
     */
    if(!strncmp("auto", k_buf + 6, 4)) 
      {
	p += 5;

        if( *p == '\0' )
            goto out;

        debug_level = simple_strtoul(p, NULL, 0);
        /* only accept 0 or 1 */
        if(!debug_level || (debug_level == 1))
          {
            printk(KERN_INFO
                   "debug_proc_write(): setting rsbac_debug_auto to %u\n",
                   debug_level);
            rsbac_debug_auto = debug_level;
            err = count;
            goto out;
          }
        else
          {
            printk(KERN_INFO
                   "debug_proc_write(): rejecting invalid debug level (should be 0 or 1)\n");
            goto out;
          }
      }
#endif /* CONFIG_RSBAC_AUTO_WRITE > 0 */
#endif /* DEBUG */

out:
  free_page((ulong) k_buf);
  return(err);
  }

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

  enum rsbac_adf_request_t        request;
  u_int                           array_version = RSBAC_ADF_REQUEST_ARRAY_VERSION;
  union rsbac_target_id_t         rsbac_target_id;
  union rsbac_attribute_value_t   rsbac_attribute_value;

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

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

  memcpy(buffer, &array_version, sizeof(array_version));
  len = sizeof(array_version);
  pos = begin + len;
  if (pos < offset)
    {
      len = 0;
      begin = pos;
    }
  if (pos > offset+length)
    goto out;

  for (request=0; request < R_NONE; request++)
    {
      memcpy(buffer+len, &(rsbac_debug_adf[request]), sizeof(int));
      len += sizeof(int);
      pos = begin + len;
      if (pos < offset)
        {
          len = 0;
          begin = pos;
        }
      if (pos > offset+length)
        goto out;
    }

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

#endif /* defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS) */

/********************************/
/*             Init             */
/********************************/

inline void __init rsbac_init_debug(void)
  {
    int i;
    #if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
    struct proc_dir_entry * tmp_entry_p;
    #endif
    
    if (!rsbac_is_initialized())
      {
#if defined(CONFIG_RSBAC_RMSG)
        /* init rsbac_console lock */
        spin_lock_init(&rsbac_log_lock);
#endif
        for (i=0;i<R_NONE;i++)
          rsbac_debug_adf[i]=rsbac_debug_adf_default;
        if(read_debug_adf_array())
          {
            printk(KERN_WARNING
                   "rsbac_init_debug(): adf log levels could not be read, using default value %i\n",
                   rsbac_debug_adf_default);
          }
        #if defined(CONFIG_RSBAC_PROC) && defined(CONFIG_PROC_FS)
        tmp_entry_p = create_proc_entry("log_levels",
                                        S_IFREG | S_IRUGO | S_IWUGO,
                                        proc_rsbac_root_p);
        if(tmp_entry_p)
          {
            tmp_entry_p->get_info = log_levels_proc_info;
            tmp_entry_p->write_proc = log_levels_proc_write;
          }

        tmp_entry_p = create_proc_entry("debug",
                                        S_IFREG | S_IRUGO | S_IWUGO,
                                        proc_rsbac_root_p);
        if(tmp_entry_p)
          {
            tmp_entry_p->get_info = debug_proc_info;
            tmp_entry_p->write_proc = debug_proc_write;
          }

        #if defined(CONFIG_RSBAC_RMSG)
        tmp_entry_p = create_proc_entry("rmsg",
                                        S_IFREG | S_IRUGO | S_IWUGO,
                                        proc_rsbac_root_p);
        if(tmp_entry_p)
          {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48)
            tmp_entry_p->ops = &proc_rmsg_inode_operations;
#else
            tmp_entry_p->proc_fops = &proc_rmsg_operations;
#endif
          }
        #endif
        tmp_entry_p = create_proc_entry(RSBAC_DEBUG_ADF_NAME,
                                        S_IFREG | S_IRUGO,
                                        proc_rsbac_backup_p);
        if(tmp_entry_p)
          {
            tmp_entry_p->get_info = dbugadf_proc_info;
            tmp_entry_p->size = sizeof(int) + R_NONE * sizeof(int);
          }
        #endif
      }
    #ifdef CONFIG_RSBAC_SOFTMODE
    if(rsbac_softmode)
      printk(KERN_DEBUG "rsbac_softmode is set\n");
    #endif
    #ifdef CONFIG_RSBAC_ALLOW_DAC_DISABLE_FULL
    if(rsbac_dac_disable)
      printk(KERN_DEBUG "rsbac_dac_disable is set\n");
    #endif
    #ifdef CONFIG_RSBAC_RMSG_NOSYSLOG
    if(rsbac_nosyslog)
      printk(KERN_DEBUG "rsbac_nosyslog is set\n");
    #endif
    if(rsbac_change_nr)
      printk(KERN_DEBUG "rsbac_change_nr is set\n");

#if defined(CONFIG_RSBAC_DEBUG)
    if(rsbac_debug_ds)
      printk(KERN_DEBUG "rsbac_debug_ds is set\n");
    if(rsbac_debug_write)
      printk(KERN_DEBUG "rsbac_debug_write is set\n");
    if(rsbac_debug_no_write)
      printk(KERN_DEBUG "rsbac_debug_no_write is set\n");
    if(rsbac_debug_stack)
      printk(KERN_DEBUG "rsbac_debug_stack is set\n");
    if(rsbac_debug_lists)
      printk(KERN_DEBUG "rsbac_debug_lists is set\n");
    if(rsbac_debug_aef)
      printk(KERN_DEBUG "rsbac_debug_aef is set\n");
    if(rsbac_debug_adf_default != 1)
      printk(KERN_DEBUG "rsbac_debug_adf_default is set to %i\n",
             rsbac_debug_adf_default);

    #if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
    if(rsbac_debug_reg)
      printk(KERN_DEBUG "rsbac_debug_reg is set\n");
    #endif

    #if defined(CONFIG_RSBAC_NET)
    if(rsbac_debug_ds_net)
      printk(KERN_DEBUG "rsbac_debug_ds_net is set\n");
    if(rsbac_debug_aef_net)
      printk(KERN_DEBUG "rsbac_debug_aef_net is set\n");
    if(rsbac_debug_adf_net)
      printk(KERN_DEBUG "rsbac_debug_adf_net is set\n");
    #endif

    #if defined(CONFIG_RSBAC_PM) || defined(CONFIG_RSBAC_PM_MAINT)
    if(rsbac_debug_ds_pm)
      printk(KERN_DEBUG "rsbac_debug_ds_pm is set\n");
    if(rsbac_debug_aef_pm)
      printk(KERN_DEBUG "rsbac_debug_aef_pm is set\n");
    if(rsbac_debug_adf_pm)
      printk(KERN_DEBUG "rsbac_debug_adf_pm is set\n");
    #endif

    #if defined(CONFIG_RSBAC_MS) || defined(CONFIG_RSBAC_MS_MAINT)
    if(rsbac_debug_adf_ms)
      printk(KERN_DEBUG "rsbac_debug_adf_ms is set\n");
    #endif

    #if defined(CONFIG_RSBAC_RC) || defined(CONFIG_RSBAC_RC_MAINT)
    if(rsbac_debug_ds_rc)
      printk(KERN_DEBUG "rsbac_debug_ds_rc is set\n");
    if(rsbac_debug_aef_rc)
      printk(KERN_DEBUG "rsbac_debug_aef_rc is set\n");
    if(rsbac_debug_adf_rc)
      printk(KERN_DEBUG "rsbac_debug_adf_rc is set\n");
    #endif

    #if defined(CONFIG_RSBAC_AUTH) || defined(CONFIG_RSBAC_AUTH_MAINT)
    if(rsbac_debug_ds_auth)
      printk(KERN_DEBUG "rsbac_debug_ds_auth is set\n");
    if(rsbac_debug_aef_auth)
      printk(KERN_DEBUG "rsbac_debug_aef_auth is set\n");
    if(rsbac_debug_adf_auth)
      printk(KERN_DEBUG "rsbac_debug_adf_auth is set\n");
    #endif

    #if defined(CONFIG_RSBAC_ACL) || defined(CONFIG_RSBAC_ACL_MAINT)
    if(rsbac_debug_ds_acl)
      printk(KERN_DEBUG "rsbac_debug_ds_acl is set\n");
    if(rsbac_debug_aef_acl)
      printk(KERN_DEBUG "rsbac_debug_aef_acl is set\n");
    if(rsbac_debug_adf_acl)
      printk(KERN_DEBUG "rsbac_debug_adf_acl is set\n");
    #endif

    #if defined(CONFIG_RSBAC_AUTO_WRITE) && (CONFIG_RSBAC_AUTO_WRITE > 0)
    if(rsbac_debug_auto)
      printk(KERN_DEBUG "rsbac_debug_auto is set\n");
    #endif
#endif /* DEBUG */
  };

#if defined(CONFIG_RSBAC_AUTO_WRITE)
int  rsbac_write_debug(boolean need_lock)
  {
    int err;

    if (!rsbac_is_initialized())
      return(0);
    if(rsbac_debug_adf_dirty)
      {
        if(need_lock)
          lock_kernel();
        rsbac_debug_adf_dirty = FALSE;
        err = write_debug_adf_array();
        if(need_lock)
          unlock_kernel();
        if(!err)
          {
#ifdef CONFIG_RSBAC_DEBUG
            if(rsbac_debug_write)
              printk(KERN_DEBUG "rsbac_write_debug(): adf log level list written\n");
#endif
            return(1);
          }
        else
          rsbac_debug_adf_dirty = TRUE;
      }
    return(0);
  };
#endif /* CONFIG_RSBAC_AUTO_WRITE */
