/*************************************************** */
/* Rule Set Based Access Control                     */
/* Implementation of the Access Control Decision     */
/* Facility (ADF) - Authentification module          */
/* File: rsbac/adf/auth/syscalls.c                   */
/*                                                   */
/* Author and (c) 1999-2001: Amon Ott <ao@rsbac.org> */
/*                                                   */
/* Last modified: 24/Aug/2001                        */
/*************************************************** */

#include <linux/string.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <rsbac/types.h>
#include <rsbac/aci.h>
#include <rsbac/error.h>
#include <rsbac/auth.h>
#include <rsbac/debug.h>
#include <rsbac/adf_main.h>

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

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

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

int rsbac_auth_add_p_cap(rsbac_pid_t pid,
                         rsbac_uid_t first_uid,
                         rsbac_uid_t last_uid)
  {
/* check only in non-maint mode */
#if !defined(CONFIG_RSBAC_MAINT)
#ifdef CONFIG_RSBAC_SWITCH
    if(rsbac_switch_auth)
#endif
      {
        union rsbac_target_id_t       i_tid;
        union rsbac_attribute_value_t i_attr_val1;

        /* check auth_may_set_cap of calling process */
        i_tid.process = current->pid;
        if (rsbac_get_attr(AUTH,
                           T_PROCESS,
                           i_tid,
                           A_auth_may_set_cap,
                           &i_attr_val1,
                           FALSE))
          {
            printk(KERN_WARNING
                   "rsbac_auth_add_p_cap(): rsbac_get_attr() returned error!\n");
            return(-RSBAC_EREADFAILED);
          }
        /* if auth_may_set_cap is not set, then reject */
        if (!i_attr_val1.auth_may_set_cap)
          {
#ifdef CONFIG_RSBAC_RMSG
            rsbac_printk(KERN_INFO
                   "rsbac_auth_add_p_cap(): adding AUTH cap %u:%u to process %u denied for process %u!\n",
                   first_uid,
                   last_uid,
                   pid,
                   current->pid);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
            printk(KERN_INFO
                   "rsbac_auth_add_p_cap(): adding AUTH cap %u:%u to process %u denied for process %u!\n",
                   first_uid,
                   last_uid,
                   pid,
                   current->pid);
#endif
            #ifdef CONFIG_RSBAC_SOFTMODE
            if(   !rsbac_softmode
            #ifdef CONFIG_RSBAC_SOFTMODE_IND
               && !rsbac_ind_softmode[AUTH]
            #endif
              )
            #endif
              return(-EPERM);
          }
      }
#endif

    /* OK, check passed. Add the capability. */
    if(rsbac_auth_add_to_p_capset(pid, first_uid, last_uid))
      {
        printk(KERN_WARNING
               "rsbac_auth_add_p_cap(): rsbac_auth_add_to_p_capset() returned error!\n");
        return(-RSBAC_EWRITEFAILED);
      }
    return 0;
  }

int rsbac_auth_remove_p_cap(rsbac_pid_t pid,
                            rsbac_uid_t first_uid,
                            rsbac_uid_t last_uid)
  {
/* check only in non-maint mode */
#if !defined(CONFIG_RSBAC_MAINT)
#ifdef CONFIG_RSBAC_SWITCH
    if(rsbac_switch_auth)
#endif
      {
        union rsbac_target_id_t       i_tid;
        union rsbac_attribute_value_t i_attr_val1;

        /* check auth_may_set_cap of calling process */
        i_tid.process = current->pid;
        if (rsbac_get_attr(AUTH,
                           T_PROCESS,
                           i_tid,
                           A_auth_may_set_cap,
                           &i_attr_val1,
                           FALSE))
          {
            printk(KERN_WARNING
                   "rsbac_auth_remove_p_cap(): rsbac_get_attr() returned error!\n");
            return(-RSBAC_EREADFAILED);
          }
        /* if auth_may_set_cap is not set, then reject */
        if (!i_attr_val1.auth_may_set_cap)
          {
#ifdef CONFIG_RSBAC_RMSG
            rsbac_printk(KERN_INFO
                   "rsbac_auth_remove_p_cap(): removing AUTH cap %u:%u from process %u denied for process %u!\n",
                   first_uid,
                   last_uid,
                   pid,
                   current->pid);
#endif
#ifndef CONFIG_RSBAC_RMSG_EXCL
            printk(KERN_INFO
                   "rsbac_auth_remove_p_cap(): removing AUTH cap %u:%u from process %u denied for process %u!\n",
                   first_uid,
                   last_uid,
                   pid,
                   current->pid);
#endif
            #ifdef CONFIG_RSBAC_SOFTMODE
            if(   !rsbac_softmode
            #ifdef CONFIG_RSBAC_SOFTMODE_IND
               && !rsbac_ind_softmode[AUTH]
            #endif
              )
            #endif
              return(-EPERM);
          }
      }
#endif

    /* OK, check passed. Try to remove the capability. */
    return(rsbac_auth_remove_from_p_capset(pid, first_uid, last_uid));
  }

int rsbac_auth_add_f_cap(rsbac_auth_file_t file,
                         rsbac_uid_t first_uid,
                         rsbac_uid_t last_uid)
  {
    /* check has been done in help/syscalls.c: sys_rsbac_auth_add_f_cap */
    if(rsbac_auth_add_to_f_capset(file, first_uid, last_uid))
      {
        printk(KERN_WARNING
               "rsbac_auth_add_f_cap(): rsbac_auth_add_to_f_capset() returned error!\n");
        return(-RSBAC_EWRITEFAILED);
      }
    return 0;
  }

int rsbac_auth_remove_f_cap(rsbac_auth_file_t file,
                            rsbac_uid_t first_uid,
                            rsbac_uid_t last_uid)
  {
    /* check has been done in help/syscalls.c: sys_rsbac_auth_remove_f_cap */
    return(rsbac_auth_remove_from_f_capset(file, first_uid, last_uid));
  }

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