/************************************************* */
/* Rule Set Based Access Control                   */
/* Implementation of the Access Control Decision   */
/* Facility (ADF) - Role Compatibility             */
/* File: rsbac/adf/rc/syscalls.c                   */
/*                                                 */
/* Author and (c) 1999,2000: Amon Ott              */
/*                                                 */
/* Last modified: 29/Nov/2000                      */
/************************************************* */

#include <linux/string.h>
#include <rsbac/types.h>
#include <rsbac/aci.h>
#include <rsbac/rc.h>
#include <rsbac/adf_main.h>
#include <rsbac/error.h>
#include <rsbac/debug.h>
#include <rsbac/helpers.h>
#include <rsbac/getname.h>
#include <rsbac/rc_getname.h>

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

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

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

#ifdef CONFIG_RSBAC_RC
/* from rsbac/adf/rc/main.c */
int rsbac_rc_test_role_admin(boolean modify);

int rsbac_rc_test_admin_roles(rsbac_rc_role_id_t t_role, boolean modify);

enum rsbac_adf_req_ret_t
         rsbac_rc_check_type_comp(enum  rsbac_target_t          target,
                                  rsbac_rc_type_id_t      type,
                            enum  rsbac_adf_request_t     request,
                                  rsbac_pid_t             caller_pid);
#endif

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

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

/* Here we only check access rights and pass on to rc_data_structures */

/* All roles are always there, so instead of creation, we supply a copy for */
/* initialization. There is always the well-defined role general to copy.   */
int rsbac_rc_sys_copy_role (rsbac_rc_role_id_t from_role,
                            rsbac_rc_role_id_t to_role)
  {
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
    if(rsbac_switch_rc)
#endif
      {
        int                           err;
        /* test admin_roles of process for source / no modify */
        if ((err=rsbac_rc_test_admin_roles(from_role, FALSE)))
          {
            if(err == -EPERM)
              {
                rsbac_uid_t user;

                if(!rsbac_get_owner(&user))
                  {
#ifdef CONFIG_RSBAC_RMSG
                    rsbac_printk(KERN_INFO
                                 "rsbac_rc_sys_copy_role(): reading role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 from_role,
                                 current->pid,
                                 user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                    printk(KERN_INFO
                           "rsbac_rc_sys_copy_role(): reading role %u denied for pid %u, user %u - not in admin_roles!\n",
                           from_role,
                           current->pid,
                           user);
#endif
                  }
              }
            return err;
          }
        /* test admin_roles of process for target / modify */
        if ((err=rsbac_rc_test_admin_roles(to_role, TRUE)))
          {
            if(err == -EPERM)
              {
                rsbac_uid_t user;

                if(!rsbac_get_owner(&user))
                  {
#ifdef CONFIG_RSBAC_RMSG
                    rsbac_printk(KERN_INFO
                                 "rsbac_rc_sys_copy_role(): changing role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 to_role,
                                 current->pid,
                                 user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                    printk(KERN_INFO
                           "rsbac_rc_sys_copy_role(): changing role %u denied for pid %u, user %u - not in admin_roles!\n",
                           to_role,
                           current->pid,
                           user);
#endif
                  }
              }
            return err;
          }
      }
#endif /* CONFIG_RSBAC_RC */

    /* pass on */
    return(rsbac_rc_copy_role(from_role, to_role));
  };

/* Getting values */
int rsbac_rc_sys_get_item (enum  rsbac_rc_target_t       target,
                           union rsbac_rc_target_id_t    tid,
                           enum  rsbac_rc_item_t         item,
                           union rsbac_rc_item_value_t * value_p)
  {
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
    if(rsbac_switch_rc)
#endif
      {
        int                           err;

        switch(item)
          {
            case RI_name:
            case RI_type_fd_name:
            case RI_type_dev_name:
            case RI_type_ipc_name:
            case RI_type_process_name:
            case RI_type_scd_name:
              /* getting names is always allowed */
              break;

            case RI_type_fd_need_secdel:
              if(target != RT_TYPE)
                return -RSBAC_EINVALIDTARGET;
              if(   (err=rsbac_rc_check_type_comp(T_FILE, tid.type, RCR_ADMIN, 0))
                 && (err=rsbac_rc_test_role_admin(FALSE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_get_item(): reading fd_need_secdel of type %u denied for pid %u, user %u - no ADMIN right!\n",
                                       tid.type,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_get_item(): reading fd_need_secdel of type %u denied for pid %u, user %u - no ADMIN right!\n",
                                 tid.type,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;

            default:
              if(target != RT_ROLE)
                return -RSBAC_EINVALIDATTR;
              /* test admin_roles or admin_type of process' role / no modify */
              if (   (err=rsbac_rc_test_admin_roles(tid.role, FALSE))
                  && (err=rsbac_rc_test_role_admin(FALSE))
                 )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_get_item(): getting item of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                       tid.role,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_get_item(): getting item of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 tid.role,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
          }
      }
#endif /* CONFIG_RSBAC_RC */

    /* pass on */
    return(rsbac_rc_get_item(target, tid, item, value_p));
  };

/* Setting values */
int rsbac_rc_sys_set_item (enum  rsbac_rc_target_t       target,
                           union rsbac_rc_target_id_t    tid,
                           enum  rsbac_rc_item_t         item,
                           union rsbac_rc_item_value_t   value)
  {
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
    if(rsbac_switch_rc)
#endif
      {
        int                           err,i;

        switch(item)
          {
          /* type targets */
            case RI_type_fd_name:
            case RI_type_fd_need_secdel:
              if(target != RT_TYPE)
                return -RSBAC_EINVALIDTARGET;
              if(   (rsbac_rc_check_type_comp(T_FILE, tid.type, RCR_ADMIN, 0) == NOT_GRANTED)
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;
                      char tmp[80];

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing %s of FD type %u denied for pid %u, user %u - no ADMIN right!\n",
                                       get_rc_item_name(tmp, item),
                                       tid.type,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing %s of FD type %u denied for pid %u, user %u - no ADMIN right!\n",
                                 get_rc_item_name(tmp, item),
                                 tid.type,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;
            case RI_type_dev_name:
              if(target != RT_TYPE)
                return -RSBAC_EINVALIDTARGET;
              if(   (rsbac_rc_check_type_comp(T_DEV, tid.type, RCR_ADMIN, 0) == NOT_GRANTED)
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing name of DEV type %u denied for pid %u, user %u - no ADMIN right!\n",
                                       tid.type,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing name of DEV type %u denied for pid %u, user %u - no ADMIN right!\n",
                                 tid.type,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;
            case RI_type_ipc_name:
              if(target != RT_TYPE)
                return -RSBAC_EINVALIDTARGET;
              if(   (rsbac_rc_check_type_comp(T_IPC, tid.type, RCR_ADMIN, 0) == NOT_GRANTED)
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing name of IPC type %u denied for pid %u, user %u - no ADMIN right!\n",
                                       tid.type,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing name of IPC type %u denied for pid %u, user %u - no ADMIN right!\n",
                                 tid.type,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;
        case RI_type_process_name:
              if(target != RT_TYPE)
                return -RSBAC_EINVALIDTARGET;
              if(   (rsbac_rc_check_type_comp(T_PROCESS, tid.type, RCR_ADMIN, 0) == NOT_GRANTED)
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing name of process type %u denied for pid %u, user %u - no ADMIN right!\n",
                                       tid.type,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing name of process type %u denied for pid %u, user %u - no ADMIN right!\n",
                                 tid.type,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;
            case RI_type_scd_name:
              if(target != RT_TYPE)
                return -RSBAC_EINVALIDTARGET;
              if(   (rsbac_rc_check_type_comp(T_SCD, tid.type, RCR_ADMIN, 0) == NOT_GRANTED)
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing name of SCD type %u denied for pid %u, user %u - no ADMIN right!\n",
                                       tid.type,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing name of SCD type %u denied for pid %u, user %u - no ADMIN right!\n",
                                 tid.type,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;

          /* roles only from here */
            case RI_role_comp:
              /* need admin for this role, assign for changed compatible roles */
              {
                union rsbac_rc_item_value_t old_value;
                      rsbac_rc_role_vector_t changes;
                union rsbac_target_id_t       i_tid;
                union rsbac_attribute_value_t i_attr_val1;
                union rsbac_rc_target_id_t    i_rc_tid;

                if(target != RT_ROLE)
                  return -RSBAC_EINVALIDATTR;
                if(!rsbac_rc_test_role_admin(TRUE))
                  break;
                /* test admin_role of process / modify */
                if((err=rsbac_rc_test_admin_roles(tid.role, TRUE)))
                  {
                    if(err == -EPERM)
                      {
                        rsbac_uid_t user;

                        if(!rsbac_get_owner(&user))
                          {
#ifdef CONFIG_RSBAC_RMSG
                            rsbac_printk(KERN_INFO
                                         "rsbac_rc_sys_set_item(): changing role_comp of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                         tid.role,
                                         current->pid,
                                         user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                            printk(KERN_INFO
                                   "rsbac_rc_sys_set_item(): changing role_comp of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                   tid.role,
                                   current->pid,
                                   user);
#endif
                          }
                      }
                    return err;
                  }
                /* now check assign for all changed comp roles. First get old role_comp */
                err = rsbac_rc_get_item(target, tid, item, &old_value);
                if(err)
                  return(err);
                changes = old_value.role_comp ^ value.role_comp;

                /* now get assign setting of caller's role */
                /* get rc_role of process */
                i_tid.process = current->pid;
                if ((err=rsbac_get_attr(T_PROCESS,
                                        i_tid,
                                        A_rc_role,
                                        &i_attr_val1,
                                        TRUE)))
                  {
                    printk(KERN_WARNING
                           "rsbac_rc_sys_set_item(): rsbac_get_attr() returned error %i!\n",err);
                    return -RSBAC_EREADFAILED;
                  }
                i_rc_tid.role = i_attr_val1.rc_role;
                /* get assign_roles of role */
                if ((err=rsbac_rc_get_item(RT_ROLE,
                                           i_rc_tid,
                                           RI_assign_roles,
                                           &old_value)))
                  {
                    printk(KERN_WARNING
                           "rsbac_rc_sys_set_item(): rsbac_rc_get_item() returned error %i!\n",err);
                    return -RSBAC_EREADFAILED;
                  }

                /* Deny, if there are changes not covered by assign vector */
                /* Note: admin_type has already been tried! */
                if((old_value.assign_roles & changes) != changes)
                  {
                    rsbac_uid_t user;
                    if(!rsbac_get_owner(&user))
                      {
#ifdef CONFIG_RSBAC_RMSG
                        rsbac_printk(KERN_INFO
                                     "rsbac_rc_sys_set_item(): changing role_comp for role %u denied for user %u, role %u - not in assign_roles!\n",
                                     tid.role,
                                     user,
                                     i_attr_val1.rc_role);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                        printk(KERN_INFO
                               "rsbac_rc_sys_set_item(): changing role_comp for role %u denied for user %u, role %u - not in assign_roles!\n",
                               tid.role,
                               user,
                               i_attr_val1.rc_role);
#endif
                      }
                    return -EPERM;
                  }
              }
              break;

            case RI_admin_type:
            case RI_admin_roles:
            case RI_assign_roles:
              /* admin_type role_admin */
              if((err=rsbac_rc_test_role_admin(TRUE)))
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;
                      char tmp[80];

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - no Role Admin!\n",
                                       get_rc_item_name(tmp, item),
                                       tid.role,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - no Role Admin!\n",
                                 get_rc_item_name(tmp, item),
                                 tid.role,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;
            case RI_name:
              /* admin for this role */
              /* test admin_role of process / modify */
              if(   (err=rsbac_rc_test_admin_roles(tid.role, TRUE))
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing name of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                       tid.role,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing name of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 tid.role,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              break;

            case RI_def_fd_create_type:
              /* admin for this role and assign for target type */
              /* test admin_role of process / modify */
              if(   (err=rsbac_rc_test_admin_roles(tid.role, TRUE))
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing def_fd_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                       tid.role,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing def_fd_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 tid.role,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              else
                {
                  enum rsbac_adf_req_ret_t result;

                  result = rsbac_rc_check_type_comp(T_FILE, value.type_id, RCR_ASSIGN, 0);
                  if(   (result == NOT_GRANTED)
                     || (result == UNDEFINED)
                    )
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing def_fd_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n",
                                       tid.role,
                                       value.type_id,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing def_fd_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n",
                                 tid.role,
                                 value.type_id,
                                 user);
#endif
                        }
                      return -EPERM;
                    }
                }
              break;
            case RI_def_process_create_type:
            case RI_def_process_chown_type:
            case RI_def_process_execute_type:
              /* admin for this role and assign for target type */
              /* test admin_role of process / modify */
              if(   (err=rsbac_rc_test_admin_roles(tid.role, TRUE))
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;
                      char tmp[80];

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                       get_rc_item_name(tmp, item),
                                       tid.role,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 get_rc_item_name(tmp, item),
                                 tid.role,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              else
                {
                  enum rsbac_adf_req_ret_t result;

                  result = rsbac_rc_check_type_comp(T_PROCESS, value.type_id, RCR_ASSIGN, 0);
                  if(   (result == NOT_GRANTED)
                     || (result == UNDEFINED)
                    )
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing def_process_*_type for role %u to %u denied for user %u - no ASSIGN right for type!\n",
                                       tid.role,
                                       value.type_id,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing def_process_*_type for role %u to %u denied for user %u - no ASSIGN right for type!\n",
                                 tid.role,
                                 value.type_id,
                                 user);
#endif
                        }
                      return -EPERM;
                    }
                }
              break;
            case RI_def_ipc_create_type:
              /* admin for this role and assign for target type */
              /* test admin_role of process / modify */
              if(   (err=rsbac_rc_test_admin_roles(tid.role, TRUE))
                 && (err=rsbac_rc_test_role_admin(TRUE))
                )
                {
                  if(err == -EPERM)
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing def_ipc_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                       tid.role,
                                       current->pid,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing def_ipc_create_type of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                 tid.role,
                                 current->pid,
                                 user);
#endif
                        }
                    }
                  return err;
                }
              else
                {
                  enum rsbac_adf_req_ret_t result;

                  result = rsbac_rc_check_type_comp(T_IPC, value.type_id, RCR_ASSIGN, 0);
                  if(   (result == NOT_GRANTED)
                     || (result == UNDEFINED)
                    )
                    {
                      rsbac_uid_t user;

                      if(!rsbac_get_owner(&user))
                        {
#ifdef CONFIG_RSBAC_RMSG
                          rsbac_printk(KERN_INFO
                                       "rsbac_rc_sys_set_item(): changing def_ipc_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n",
                                       tid.role,
                                       value.type_id,
                                       user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                          printk(KERN_INFO
                                 "rsbac_rc_sys_set_item(): changing def_ipc_create_type for role %u to %u denied for user %u - no ASSIGN right for type!\n",
                                 tid.role,
                                 value.type_id,
                                 user);
#endif
                        }
                      return -EPERM;
                    }
                }
              break;

            case RI_type_comp_fd:
            case RI_type_comp_dev:
            case RI_type_comp_process:
            case RI_type_comp_ipc:
            case RI_type_comp_scd:
              {
                union rsbac_rc_item_value_t old_value, my_value;
                union rsbac_target_id_t       i_tid;
                union rsbac_attribute_value_t i_attr_val1;
                union rsbac_rc_target_id_t    i_rc_tid;

                if(target != RT_ROLE)
                  return -RSBAC_EINVALIDATTR;
                if(!rsbac_rc_test_role_admin(TRUE))
                  break;
                /* test admin_role of process / modify */
                if((err=rsbac_rc_test_admin_roles(tid.role, TRUE)))
                  {
                    if(err == -EPERM)
                      {
                        rsbac_uid_t user;
                        char tmp[80];

                        if(!rsbac_get_owner(&user))
                          {
#ifdef CONFIG_RSBAC_RMSG
                            rsbac_printk(KERN_INFO
                                         "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                         get_rc_item_name(tmp, item),
                                         tid.role,
                                         current->pid,
                                         user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                            printk(KERN_INFO
                                   "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - not in admin_roles!\n",
                                   get_rc_item_name(tmp, item),
                                   tid.role,
                                   current->pid,
                                   user);
#endif
                          }
                      }
                    return err;
                  }
                /* test caller's RCR_ACCESS_CONTROL for all types we change normal access */
                /* and caller's RCR_SUPERVISOR for all types we change special rights for */
                /* first get old setting */
                err = rsbac_rc_get_item(target, tid, item, &old_value);
                if(err)
                  return(err);

                /* get rc_role of process */
                i_tid.process = current->pid;
                if ((err=rsbac_get_attr(T_PROCESS,
                                        i_tid,
                                        A_rc_role,
                                        &i_attr_val1,
                                        TRUE)))
                  {
                    printk(KERN_WARNING
                           "rsbac_rc_sys_set_item(): rsbac_get_attr() returned error %i!\n",err);
                    return err;
                  }
                /* get item of process role */
                i_rc_tid.role = i_attr_val1.rc_role;
                if ((err=rsbac_rc_get_item(RT_ROLE,
                                           i_rc_tid,
                                           item,
                                           &my_value)))
                  {
                    printk(KERN_WARNING
                           "rsbac_rc_sys_set_item(): rsbac_rc_get_item() returned error %i!\n",err);
                    return err;
                  }

                /* check planned changes for all types */
                for(i=0; i<RSBAC_RC_NR_TYPES; i++)
                  {
                    if(   /* Want to change normal rights to this type? Need RCR_ACCESS_CONTROL. */
                          (   (   (old_value.type_comp[i] & RSBAC_ALL_REQUEST_VECTOR)
                               != (value.type_comp[i] & RSBAC_ALL_REQUEST_VECTOR)
                              )
                           && (!(my_value.type_comp[i] & RSBAC_RC_RIGHTS_VECTOR(RCR_ACCESS_CONTROL)))
                          )
                       ||    
                          /* Want to change special rights to this type? Need RCR_SUPERVISOR. */
                          (   (   (old_value.type_comp[i] & RSBAC_RC_SPECIAL_RIGHTS_VECTOR)
                               != (value.type_comp[i] & RSBAC_RC_SPECIAL_RIGHTS_VECTOR)
                              )
                           && (!(my_value.type_comp[i] & RSBAC_RC_RIGHTS_VECTOR(RCR_SUPERVISOR)))
                          )
                      )
                      {
                        /* check failed. Last resort: Classical admin_type. */
                        if((err=rsbac_rc_test_role_admin(TRUE)))
                          {
                            if(err == -EPERM)
                              {
                                rsbac_uid_t user;
                                char tmp[80];

                                if(!rsbac_get_owner(&user))
                                  {
#ifdef CONFIG_RSBAC_RMSG
                                    rsbac_printk(KERN_INFO
                                                 "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - insufficent rights!\n",
                                                 get_rc_item_name(tmp, item),
                                                 tid.role,
                                                 current->pid,
                                                 user);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                                    printk(KERN_INFO
                                           "rsbac_rc_sys_set_item(): changing %s of role %u denied for pid %u, user %u - insufficent rights!\n",
                                           get_rc_item_name(tmp, item),
                                           tid.role,
                                           current->pid,
                                           user);
#endif
                                  }
                              }
                            return err;
                          }
                      }
                  }
              }
              break;

            default:
              return -RSBAC_EINVALIDATTR;
          }
      }
#endif /* CONFIG_RSBAC_RC */

    /* pass on */
    return(rsbac_rc_set_item(target, tid, item, value));
  };

/* Set own role, if allowed ( = in role_comp vector of current role) */
int rsbac_rc_sys_change_role (rsbac_rc_role_id_t role)
  {
    union rsbac_target_id_t       i_tid;
    union rsbac_attribute_value_t i_attr_val1;
#ifdef CONFIG_RSBAC_RC
#ifdef CONFIG_RSBAC_SWITCH
    if(rsbac_switch_rc)
#endif
      {
        int                           err;
        union rsbac_rc_target_id_t    i_rc_tid;
        union rsbac_rc_item_value_t   i_rc_item_val1;

        i_tid.process = current->pid;
        /* get rc_role of process */
        if ((err=rsbac_get_attr(T_PROCESS,
                                i_tid,
                                A_rc_role,
                                &i_attr_val1,
                                TRUE)))
          {
            printk(KERN_WARNING
                   "rsbac_rc_sys_change_role(): rsbac_get_attr() returned error %i!\n",err);
            return -RSBAC_EREADFAILED;
          }

        /* get role_comp of role */
        i_rc_tid.role = i_attr_val1.rc_role;
        if ((err=rsbac_rc_get_item(RT_ROLE,
                                   i_rc_tid,
                                   RI_role_comp,
                                   &i_rc_item_val1)))
          {
            printk(KERN_WARNING
                   "rsbac_rc_sys_change_role(): rsbac_rc_get_item() returned error %i!\n",err);
            return -RSBAC_EREADFAILED;
          }

        /* deny, if old role is not compatible with new role */
        if (!(i_rc_item_val1.role_comp & ((rsbac_rc_role_vector_t) 1 << role) ))
          {
            rsbac_uid_t user;

            if(!rsbac_get_owner(&user))
              {
#ifdef CONFIG_RSBAC_RMSG
                rsbac_printk(KERN_INFO
                             "rsbac_rc_sys_change role(): changing from role %u to %u denied for pid %u, user %u, role %u - roles not compatible!\n",
                             i_attr_val1.rc_role,
                             role,
                             i_tid.process,
                             user,
                             i_attr_val1.rc_role);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
                printk(KERN_INFO
                       "rsbac_rc_sys_change role(): changing from role %u to %u denied for pid %u, user %u, role %u - roles not compatible!\n",
                       i_attr_val1.rc_role,
                       role,
                       i_tid.process,
                       user,
                       i_attr_val1.rc_role);
#endif
              }
            return -EPERM;
          }
      }
#endif /* CONFIG_RSBAC_RC */

    /* OK, check passed. Set role. */
    i_tid.process = current->pid;
    i_attr_val1.rc_role = role;
    if (rsbac_set_attr(T_PROCESS,
                       i_tid,
                       A_rc_role,
                       i_attr_val1))
      { /* failed! */
        printk(KERN_WARNING "rsbac_rc_sys_change_role(): rsbac_set_attr() returned error!\n");
        return(-RSBAC_EWRITEFAILED);
      }
    /* Ready. */
    return(0);
  };

/* Getting own effective rights */
int rsbac_rc_sys_get_eff_rights (enum  rsbac_target_t       target,
                                 union rsbac_target_id_t    tid,
                                       rsbac_rc_request_vector_t * request_vector)
  {
    union rsbac_target_id_t       i_tid;
    enum  rsbac_attribute_t       i_attr = A_none;
    union rsbac_attribute_value_t i_attr_val1;
    int                           err;
    enum  rsbac_rc_item_t         i_rc_item;
    union rsbac_rc_target_id_t    i_rc_tid;
    union rsbac_rc_item_value_t   i_rc_item_val1;

    i_tid.process = current->pid;
    /* get rc_role of process */
    if ((err=rsbac_get_attr(T_PROCESS,
                       i_tid,
                       A_rc_role,
                       &i_attr_val1,
                       TRUE)))
      {
        printk(KERN_WARNING
               "rsbac_rc_sys_get_eff_rights(): rsbac_get_attr() returned error %i!\n",err);
        return -RSBAC_EREADFAILED;
      }

    switch(target)
      {
        case T_FILE:
        case T_DIR:
          i_attr = A_rc_type_fd;
          i_rc_item = RI_type_comp_fd;
          break;
        case T_DEV:
          i_attr = A_rc_type;
          i_rc_item = RI_type_comp_dev;
          break;
        case T_IPC:
          i_attr = A_rc_type;
          i_rc_item = RI_type_comp_ipc;
          break;
        case T_PROCESS:
          i_attr = A_rc_type;
          i_rc_item = RI_type_comp_process;
          break;
        case T_SCD: /* special case! */
          if(tid.scd >= RSBAC_RC_MAX_TYPE)
            return -RSBAC_EINVALIDTARGET;
          i_rc_item = RI_type_comp_scd;
          break;
        default:
          return -RSBAC_EINVALIDTARGET;
      }
    /* get type_comp_xxx of role for target */
    i_rc_tid.role = i_attr_val1.rc_role;
    if ((err=rsbac_rc_get_item(RT_ROLE,
                                i_rc_tid,
                                i_rc_item,
                                &i_rc_item_val1)))
      {
        printk(KERN_WARNING
               "rsbac_rc_sys_get_eff_rights(): rsbac_rc_get_item() returned error %i!\n",err);
        return -RSBAC_EREADFAILED;
      }

    /* get rc_type of target */
    if(target == T_SCD)
      {
        i_attr_val1.rc_type = tid.scd;
      }
    else
      {
        if ((err=rsbac_get_attr(target,
                                tid,
                                i_attr,
                                &i_attr_val1,
                                TRUE)))
          {
            printk(KERN_WARNING
                   "rsbac_rc_sys_get_eff_rights(): rsbac_get_attr() returned error %i!\n",err);
            return -RSBAC_EREADFAILED;
          }
      }

    /* extract value */
    *request_vector = i_rc_item_val1.type_comp[i_attr_val1.rc_type];
    /* Ready. */
    return(0);
  };

/* end of rsbac/adf/rc/syscalls.c */
