/************************************* */
/* Rule Set Based Access Control       */
/* Author and (c) 1999,2000: Amon Ott  */
/* Helper functions for all parts      */
/* Last modified: 15/Oct/2000          */
/************************************* */

#include <rsbac/types.h>
#include <rsbac/getname.h>
#include <rsbac/helpers.h>
#include <rsbac/error.h>

#ifdef __KERNEL__
#include <linux/string.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#else
#include <string.h>
#endif

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

static char  request_list[R_NONE+1][24] = {
                        "ADD_TO_KERNEL",
                        "ALTER",
                        "APPEND_OPEN",
                        "CHANGE_GROUP",
                        "CHANGE_OWNER",
                        "CHDIR",
                        "CLONE",
                        "CLOSE",
                        "CREATE",
                        "DELETE",
                        "EXECUTE",
                        "GET_PERMISSIONS_DATA",
                        "GET_STATUS_DATA",
                        "LINK_HARD",
                        "MODIFY_ACCESS_DATA",
                        "MODIFY_ATTRIBUTE",
                        "MODIFY_PERMISSIONS_DATA",
                        "MODIFY_SYSTEM_DATA",
                        "MOUNT",
                        "READ",
                        "READ_ATTRIBUTE",
                        "READ_WRITE_OPEN",
                        "READ_OPEN",
                        "REMOVE_FROM_KERNEL",
                        "RENAME",
                        "SEARCH",
                        "SEND_SIGNAL",
                        "SHUTDOWN",
                        "SWITCH_LOG",
                        "SWITCH_MODULE",
                        "TERMINATE",
                        "TRACE",
                        "TRUNCATE",
                        "UMOUNT",
                        "WRITE",
                        "WRITE_OPEN",
                        "NONE" };

static char  result_list[UNDEFINED+1][12] = {
                         "NOT_GRANTED",
                         "GRANTED",
                         "DO_NOT_CARE",
                         "UNDEFINED" };

static char  attribute_list[A_none+1][21] = {
                          "owner",
                          "pseudo",
                          "security_level",
                          "mac_categories",
                          "object_category",
                          "data_type",
                          "system_role",
                          "current_sec_level",
                          "mac_curr_categories",
                          "min_write_open",
                          "min_write_categories",
                          "max_read_open",
                          "max_read_categories",
                          "mac_auto",
                          "mac_trusted",
                          "mac_trusted_for_user",
                          "mac_check",
                          "pm_role",
                          "pm_process_type",
                          "pm_current_task",
                          "pm_object_class",
                          "pm_ipc_purpose",
                          "pm_object_type",
                          "pm_program_type",
                          "pm_tp",
                          "pm_task_set",
                          "ms_scanned",
                          "ms_trusted",
                          "ms_backbuf",
                          "ms_buflen",
                          "ms_str_nr",
                          "ms_str_offset",
                          "ms_sock_trusted_tcp",
                          "ms_sock_trusted_udp",
                          "ff_flags",
                          "rc_type",
                          "rc_type_fd",
                          "rc_force_role",
                          "rc_role",
                          "rc_def_role",
                          "auth_may_setuid",
                          "auth_may_set_cap",
                          "log_array_low",
                          "log_array_high",
                          "log_program_based",
                          "log_user_based",
#ifdef __KERNEL__
                          /* adf-request helpers */
                          "group",
                          "sockaddr",
                          "signal",
                          "mode",
                          "nlink",
                          "switch_target",
                          "mod_name",
                          "request",
                          "ms_segment",
                          "trace_request",
                          "auth_add_f_cap",
                          "auth_remove_f_cap",
                          "auth_get_caplist",
                          "prot_bits",
#endif
                          "none" };

static char  target_list[T_NONE+1][8] = {
                          "FILE",
                          "DIR",
                          "DEV",
                          "IPC",
                          "SCD",
                          "USER",
                          "PROCESS",
#ifndef __KERNEL__
                          "FD",
#endif
                          "NONE" };

static char  ipc_target_list[I_none+1][7] = {
                          "sem",
                          "msg",
                          "shm",
                          "sock",
                          "sockid",
                          "fifo",
                          "none" };

static char  switch_target_list[SW_NONE+1][5] = {
                          "MAC",
                          "FC",
                          "SIM",
                          "PM",
                          "MS",
                          "FF",
                          "RC",
                          "AUTH",
                          "REG",
                          "ACL",
                          "NONE" };

static char  error_list[RSBAC_EDECISIONMISMATCH][25] = {
                          "RSBAC_EPERM",
                          "RSBAC_EACCESS",
                          "RSBAC_EREADFAILED",
                          "RSBAC_EWRITEFAILED",
                          "RSBAC_EINVALIDPOINTER",
                          "RSBAC_ENOROOTDIR",
                          "RSBAC_EPATHTOOLONG",
                          "RSBAC_ENOROOTDEV",
                          "RSBAC_ENOTFOUND",
                          "RSBAC_ENOTINITIALIZED",
                          "RSBAC_EREINIT",
                          "RSBAC_ECOULDNOTADDDEVICE",
                          "RSBAC_ECOULDNOTADDITEM",
                          "RSBAC_ECOULDNOTCREATEPATH",
                          "RSBAC_EINVALIDATTR",
                          "RSBAC_EINVALIDDEV",
                          "RSBAC_EINVALIDTARGET",
                          "RSBAC_EINVALIDVALUE",
                          "RSBAC_EEXISTS",
                          "RSBAC_EINTERNONLY",
                          "RSBAC_EINVALIDREQUEST",
                          "RSBAC_ENOTWRITABLE",
                          "RSBAC_EMALWAREDETECTED",
                          "RSBAC_ENOMEM",
                          "RSBAC_EDECISIONMISMATCH"};

static char scd_type_list[ST_none+1][12] = {
                          "time_strucs",
                          "clock",
                          "host_id",
                          "net_id",
                          "ioports",
                          "rlimit",
                          "swap",
                          "syslog",
                          "rsbac",
                          "rsbac_log",
                          "other",
                          "kmem",
                          "none" };

/* Attribute types */

#ifndef __KERNEL__
static char  attribute_param_list[A_none+1][165] = {
                          "\t\tuser-ID (non-negative integer)",
                          "\t\tuser-pseudo (positive long integer)",
                          "\t0 = unclassified, 1 = confidential, 2 = secret,\n\t\t\t3 = top secret, 254 = inherit, max. level 252",
                          "\tBit Set String of length 64 for all categories",
                          "0 = general, 1 = security, 2 = system, 3 = inherit",
                          "\t0 = none, 1 = CDI, 2 = CDIIC, 3 = SI, 4 = inherit",
                          "\t0 = user, 1 = security officer, 2 = administrator",
                          "0 = unclassified, 1 = confidential, 2 = secret,\n\t\t\t3 = top secret, max. level 252",
                          "\tBit Set String of length 64 for all categories",
                          "\t0 = unclassified, 1 = confidential, 2 = secret,\n\t\t\t3 = top secret, max. level 252",
                          "\tBit Set String of length 64 for all categories",
                          "\t0 = unclassified, 1 = confidential, 2 = secret,\n\t\t\t3 = top secret, max. level 252",
                          "\tBit Set String of length 64 for all categories",
                          "\t0 = false, 1 = true",
                          "\t0 = false, 1 = true",
                          "-3 = no user, -4 = all users, user-ID = for this user",
                          "\t0 = false, 1 = true",
                          "\t0 = user, 1 = security officer,\n\t\t\t2 = data protection officer, 3 = TP-manager,\n\t\t\t4 = system-admin, 5 = inherit",
                          "0 = none, 1 = TP",
                          "Task-ID (positive integer)",
                          "Class-ID (positive integer)",
                          "\tPurpose-ID (positive integer)",
                          "\t0 = none, 1 = TP, 2 = personal data,\n\t\t\t3 = non-personal data, 4 = ipc, 5 = dir",
                          "0 = none, 1 = TP",
                          "\t\tTP-ID (positive integer)",
                          "\tpm-task-list-ID (positive integer)",
                          "\t0 = unscanned, 1 = rejected, >=2 = accepted with level",
                          "\t0 = not_trusted, 1 = read trusted, 2 = full trusted",
                          "\t(internal only, do not set)",
                          "\t(internal only, do not set)",
                          "\t(internal only, do not set)",
                          "\t(internal only, do not set)",
                          "0 = not_trusted, 1 = active, 2 = full",
                          "0 = not_trusted, 1 = active, 2 = full",
                          "\t1 = read_only, 2 = execute_only, 4 = search_only\n\t\t\t8 = write_only, 16 = secure_delete, 128 = add_inherited\n\t\t\t(or'd)",
                          "\tRC-type-id (0-63)",
                          "\tRC-type-id (0-63) or 65 = inherit from parent",
                          "\tRC-role-id (0-63) or 64 = inherit_user,\n\t\t\t65 = inherit_process (keep), 66 = inherit_parent (default),\n\t\t\t67 = inherit_user_on_chown_only (root default)",
                          "\tRC-role-id (0-63)",
                          "\tRC-role-id (0-63)",
                          "0 = false, 1 = true",
                          "0 = false, 1 = true",
                          "\tBit-String for all Requests, low bit",
                          "\tBit-String for all Requests, high bit\n (l=0,h=0 = none, l=1,h=0 = denied, l=0,h=1 = full, l=1,h=1 = request based)",
                          "Bit-String for all Requests",
                          "\tBit-String for all Requests",
                          "\t\tINVALID!" };
#endif

static char  log_level_list[LL_invalid+1][9] = {
                          "none",
                          "denied",
                          "full",
                          "request",
                          "invalid!" };

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

#ifdef __KERNEL__
#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(get_request_name);
#endif
#endif

char * get_request_name(char * request_name,
                        enum  rsbac_adf_request_t request)
  {
    if(!request_name)
      return(NULL);
    if(request >= R_NONE)
      strcpy(request_name, "ERROR!");
    else
      strcpy(request_name, request_list[request]);
    return(request_name);
  };

enum   rsbac_adf_request_t get_request_nr(const char * request_name)
  {
     enum  rsbac_adf_request_t i;
    
    if(!request_name)
      return(R_NONE);
    for (i = 0; i < R_NONE; i++)
      {
        if (!strcmp(request_name,request_list[i]))
          {
            return(i);
          }
      }
    return(R_NONE);
  };


char * get_result_name(char * res_name,
                       enum   rsbac_adf_req_ret_t res)
  {
    if(!res_name)
      return(NULL);
    if(res > UNDEFINED)
      strcpy(res_name, "ERROR!");
    else
      strcpy(res_name, result_list[res]);
    return(res_name);
  };

enum   rsbac_adf_req_ret_t get_result_nr(const char * res_name)
  {
     enum  rsbac_adf_req_ret_t i;
    
    if(!res_name)
      return(UNDEFINED);
    for (i = 0; i < UNDEFINED; i++)
      {
        if (!strcmp(res_name,result_list[i]))
          {
            return(i);
          }
      }
    return(UNDEFINED);
  };


#ifdef __KERNEL__
#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(get_attribute_name);
#endif
#endif

char * get_attribute_name(     char *            attr_name,
                          enum rsbac_attribute_t attr)
  {
    if(!attr_name)
      return(NULL);
    if(attr > A_none)
      strcpy(attr_name, "ERROR!");
    else
      strcpy(attr_name, attribute_list[attr]);
    return(attr_name);
  };

enum   rsbac_attribute_t get_attribute_nr(const char * attr_name)
  {
     enum  rsbac_attribute_t i;
    
    if(!attr_name)
      return(A_none);
    for (i = 0; i < A_none; i++)
      {
        if (!strcmp(attr_name,attribute_list[i]))
          {
            return(i);
          }
      }
    return(A_none);
  };


#ifdef __KERNEL__
#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(get_scd_type_name);
#endif
#endif

char * get_scd_type_name(char * res_name,
                         enum   rsbac_scd_type_t res)
  {
    if(!res_name)
      return(NULL);
    if(res > ST_none)
      strcpy(res_name, "ERROR!");
    else
      strcpy(res_name, scd_type_list[res]);
    return(res_name);
  };

enum   rsbac_scd_type_t get_scd_type_nr(const char * res_name)
  {
     enum  rsbac_scd_type_t i;
    
    if(!res_name)
      return(ST_none);
    for (i = 0; i < ST_none; i++)
      {
        if (!strcmp(res_name, scd_type_list[i]))
          {
            return(i);
          }
      }
    return(ST_none);
  };


#ifdef __KERNEL__
#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(get_target_name);
#endif
#endif

char * get_target_name(char * target_type_name,
                       enum   rsbac_target_t target,
                       char * target_id_name,
                       union  rsbac_target_id_t tid)
  {
#ifdef __KERNEL__
    char * help_name;
#else
    char help_name[RSBAC_MAXNAMELEN+4];
#endif

    if(!target_type_name || !target_id_name)
      return(NULL);

#ifdef __KERNEL__
    #ifdef CONFIG_RSBAC_LOG_FULL_PATH
    help_name = kmalloc(CONFIG_RSBAC_MAX_PATH_LEN + 4, GFP_KERNEL);
    #else
    help_name = kmalloc(RSBAC_MAXNAMELEN + 4, GFP_KERNEL);
    #endif
    if(!help_name)
      return NULL;
#endif

    switch(target)
      {
#ifdef __KERNEL__
        case T_FILE:    strcpy (target_type_name, "FILE");
                        strcpy (target_id_name, "Device ");
                        ulongtostr(help_name, MAJOR(tid.file.device));
                        strcat(target_id_name, help_name);
                        strcat(target_id_name, ":");
                        ulongtostr(help_name, MINOR(tid.file.device));
                        strcat(target_id_name, help_name);
                        strcat(target_id_name, " Inode ");
                        ulongtostr(help_name, tid.file.inode);
                        strcat(target_id_name, help_name);
                        if(   tid.file.dentry_p
                           && tid.file.dentry_p->d_name.name
                           && tid.file.dentry_p->d_name.len
                          )
                          {
                            #ifdef CONFIG_RSBAC_LOG_FULL_PATH
                              if(get_full_path(tid.file.dentry_p, help_name,
                                               CONFIG_RSBAC_MAX_PATH_LEN) > 0)
                                {
                                  strcat(target_id_name, " Path ");
                                  strcat(target_id_name, help_name);
                                }
                            #else
                              int namelen = min(tid.file.dentry_p->d_name.len, RSBAC_MAXNAMELEN);

                              strcat(target_id_name, " Name ");
                              strncpy(help_name, tid.file.dentry_p->d_name.name, namelen);
                              help_name[namelen]=0;
                              strcat(target_id_name, help_name);
                            #endif
                          }
                        break;
        case T_DIR:     strcpy (target_type_name, "DIR");
                        strcpy (target_id_name, "Device ");
                        ulongtostr(help_name, MAJOR(tid.dir.device));
                        strcat(target_id_name, help_name);
                        strcat(target_id_name, ":");
                        ulongtostr(help_name, MINOR(tid.dir.device));
                        strcat(target_id_name, help_name);
                        strcat(target_id_name, " Inode ");
                        ulongtostr(help_name, tid.dir.inode);
                        strcat(target_id_name, help_name);
                        if(   tid.dir.dentry_p
                           && tid.dir.dentry_p->d_name.name
                           && tid.dir.dentry_p->d_name.len
                          )
                          {
                            #ifdef CONFIG_RSBAC_LOG_FULL_PATH
                              if(get_full_path(tid.file.dentry_p, help_name,
                                               CONFIG_RSBAC_MAX_PATH_LEN) > 0)
                                {
                                  strcat(target_id_name, " Path ");
                                  strcat(target_id_name, help_name);
                                }
                            #else
                              int namelen = min(tid.file.dentry_p->d_name.len, RSBAC_MAXNAMELEN);

                              strcat(target_id_name, " Name ");
                              strncpy(help_name, tid.file.dentry_p->d_name.name, namelen);
                              help_name[namelen]=0;
                              strcat(target_id_name, help_name);
                            #endif
                          }
                        break;
        case T_DEV:     strcpy (target_type_name, "DEV");
                        if(tid.dev.type == D_block)
                          strcpy (target_id_name, "block ");
                        else
                          strcpy (target_id_name, "char ");
                        ulongtostr(help_name, MAJOR(tid.dev.id));
                        strcat(target_id_name, help_name);
                        strcat(target_id_name, ":");
                        ulongtostr(help_name, MINOR(tid.dev.id));
                        strcat(target_id_name, help_name);
                        break;
#endif
        case T_IPC:     strcpy (target_type_name, "IPC");
                        switch (tid.ipc.type)
                          {
                            case I_sem: strcpy(target_id_name, "Sem-ID ");
                                        break;
                            case I_msg: strcpy(target_id_name, "Msg-ID ");
                                        break;
                            case I_shm: strcpy(target_id_name, "Shm-ID ");
                                        break;
                            case I_sock: strcpy(target_id_name, "Sock-ID ");
                                        break;
                            case I_fifo: strcpy(target_id_name, "Fifo-ID ");
                                        break;
                            default:    strcpy(target_id_name, "???-ID ");
                                        break;
                          };
                        ulongtostr(help_name, tid.ipc.id.id_nr);
                        strcat(target_id_name, help_name);
                        break;
        case T_SCD:     strcpy (target_type_name, "SCD");
                        get_scd_type_name(target_id_name, tid.scd);
                        break;
        case T_USER:    strcpy (target_type_name, "USER");
                        inttostr(target_id_name, tid.user);
                        break;
        case T_PROCESS: strcpy (target_type_name, "PROCESS");
                        ulongtostr(target_id_name, tid.process);
                        break;
        case T_NONE:    strcpy (target_type_name, "NONE");
                        strcpy (target_id_name, "NONE");
                        break;
        default:        strcpy (target_type_name, "ERROR!!!");
                        strcpy (target_id_name, "ERROR!!!");
      };
#ifdef __KERNEL__
    kfree(help_name);
#endif
    return(target_type_name);
  };

enum   rsbac_target_t get_target_nr(const char * target_name)
  {
     enum  rsbac_target_t i;
    
    if(!target_name)
      return(T_NONE);
    for (i = 0; i < T_NONE; i++)
      {
        if (!strcmp(target_name,target_list[i]))
          {
            return(i);
          }
      }
    return(T_NONE);
  };

char * get_ipc_target_name(char * ipc_name,
                        enum  rsbac_ipc_type_t target)
  {
    if(!ipc_name)
      return(NULL);
    if(target > I_none)
      strcpy(ipc_name, "ERROR!");
    else
      strcpy(ipc_name, ipc_target_list[target]);
    return(ipc_name);
  };

enum   rsbac_ipc_type_t get_ipc_target_nr(const char * ipc_name)
  {
     enum  rsbac_ipc_type_t i;
    
    if(!ipc_name)
      return(I_none);
    for (i = 0; i < I_none; i++)
      {
        if (!strcmp(ipc_name,ipc_target_list[i]))
          {
            return(i);
          }
      }
    return(I_none);
  };


#ifdef __KERNEL__
#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(get_switch_target_name);
#endif
#endif

char * get_switch_target_name(char * switch_name,
                        enum  rsbac_switch_target_t target)
  {
    if(!switch_name)
      return(NULL);
    if(target > SW_NONE)
      strcpy(switch_name, "ERROR!");
    else
      strcpy(switch_name, switch_target_list[target]);
    return(switch_name);
  };

enum   rsbac_switch_target_t get_switch_target_nr(const char * switch_name)
  {
     enum  rsbac_switch_target_t i;
    
    if(!switch_name)
      return(SW_NONE);
    for (i = 0; i < SW_NONE; i++)
      {
        if (!strcmp(switch_name,switch_target_list[i]))
          {
            return(i);
          }
      }
    return(SW_NONE);
  };


#ifdef __KERNEL__
#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(get_error_name);
#endif
#endif

char * get_error_name(char * error_name,
                      int error)
  {
    if(!error_name)
      return(NULL);
    if(RSBAC_ERROR(error))
      strcpy(error_name, error_list[(-error)-RSBAC_EPERM]);
    else
      #ifdef __KERNEL__ 
      inttostr(error_name, error);
      #else
      strcpy(error_name, strerror(-error));
      #endif
    return(error_name);
  };

#ifndef __KERNEL__
char * get_attribute_param(     char *            attr_name,
                          enum rsbac_attribute_t attr)
  {
    if(!attr_name)
      return(NULL);
    if(attr > A_none)
      strcpy(attr_name, "ERROR!");
    else
      strcpy(attr_name, attribute_param_list[attr]);
    return(attr_name);
  };
#endif

char * get_log_level_name(char * ll_name,
                        enum  rsbac_log_level_t target)
  {
    if(!ll_name)
      return(NULL);
    if(target > LL_invalid)
      strcpy(ll_name, "ERROR!");
    else
      strcpy(ll_name, log_level_list[target]);
    return(ll_name);
  };

enum   rsbac_log_level_t get_log_level_nr(const char * ll_name)
  {
     enum  rsbac_log_level_t i;
    
    if(!ll_name)
      return(LL_invalid);
    for (i = 0; i < LL_invalid; i++)
      {
        if (!strcmp(ll_name,log_level_list[i]))
          {
            return(i);
          }
      }
    return(LL_invalid);
  };

