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

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

#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
#include <linux/slab.h>
#endif
#include <linux/mm.h>
#include <rsbac/aci.h>
#endif
#ifndef __KERNEL__
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#endif

char * inttostr(char * str, int i)
  {
    int j = 0;
    
    if(!str)
      return(NULL);
      
    if (i<0)
      {
        str[j] = '-';
        j++;
        i = -i;
      }
    if (i>=10000)
      {
        str[j] = '0' + (i / 10000);
        j++;
      }
    if (i>=1000)
      {
        str[j] = '0' + ((i % 10000) / 1000);
        j++;
      }
    if (i>=100)
      {
        str[j] = '0' + ((i % 1000) / 100);
        j++;
      }
    if (i>=10)
      {
        str[j] = '0' + ((i % 100) / 10);
        j++;
      }
    str[j] = '0' + (i % 10);
    j++;
    str[j] = 0;
    return (str);
  };

char * ulongtostr(char * str, u_long i)
  {
    int    j = 0;
    u_long k = 1000000000;
    
    if(!str)
      return(NULL);

    if (i>=k)
      {
        str[j] = '0' + ((i / k) % 100);
        j++;
      }
    k /= 10;

    while (k>1)
      {
        if (i>=k)
          {
            str[j] = '0' + ((i % (k*10)) / k);
            j++;
          }
        k /= 10;
      };

    str[j] = '0' + (i % 10);
    j++;
    str[j] = 0;
    return (str);
  };

char * longtostr(char * str, long i)
  {
    int    j = 0;
    u_long k = 1000000000;
    
    if(!str)
      return(NULL);

    if (i<0)
      {
        str[0] = '-';
        j = 1;
        i = -i;
      }
    if (i>=k)
      {
        str[j] = '0' + ((i / k) % 100);
        j++;
      }
    k /= 10;

    while (k>1)
      {
        if (i>=k)
          {
            str[j] = '0' + ((i % (k*10)) / k);
            j++;
          }
        k /= 10;
      };

    str[j] = '0' + (i % 10);
    j++;
    str[j] = 0;
    return (str);
  };

#ifndef __KERNEL__

void error_exit(int error)
  {
    char tmp1[80];

    if(error<0)
      {
        get_error_name(tmp1,error);
        fprintf(stderr, "Error: %s\n", tmp1);
        exit(1);
      }
  }

void show_error(int error)
  {
    char tmp1[80];

    if(error<0)
      {
        get_error_name(tmp1,error);
        fprintf(stderr, "Error: %s\n", tmp1);
      }
  }

rsbac_uid_t get_user(char * name)
  {
    struct passwd * user_info_p;

    if(   (!(user_info_p = getpwnam(name)))
       && (   (!(user_info_p = getpwuid(strtol(name,0,0))))
           || (!(user_info_p->pw_uid) && strcmp("0",name)) )
      )
      {
        fprintf(stderr, "Invalid user %s!\n", name);
        exit(1);
      }
    return user_info_p->pw_uid;
  }

char * get_user_name(rsbac_uid_t user, char * name)
  {
    struct passwd * user_info_p;

    if((user_info_p = getpwuid(user)))
      {
        strcpy(name, user_info_p->pw_name);
      }
    else
      {
        strcpy(name, "*unknown*");
      }
    return name;
  }


char * u64tostrlog(char * str, __u64 i)
  {
    int    j = 0;
    __u64  k;

    if(!str)
      return(NULL);

    k = 1;
    for(j = R_NONE - 1;j >= 0;j--)
      {
        if (i & k)
          str[j] = '1';
        else
          str[j] = '0';
        k<<=1;
      };

    str[R_NONE] = 0;
    return (str);
  };

__u64 strtou64log(char * str, __u64 * i_p)
  {
    int    j;
    __u64  k = 1, res=0;
    
    if(!str)
      return(0);

    if (strlen(str) < R_NONE)
      return(-1);
    for(j=R_NONE-1;j>=0;j--)
      {
        if(str[j] != '0')
          {
            res |= k;
          }
        k <<= 1;
      }
    for(j=R_NONE;j<64;j++)
      {
        res |= k;
        k <<= 1;
      }
    *i_p = res;
    return(res);
  };

char * u64tostrrc(char * str, __u64 i)
  {
    int    j = 0;
    __u64  k;

    if(!str)
      return(NULL);

    k = 1;
    for(j = RSBAC_RC_MAX_ROLE;j >= 0;j--)
      {
        if (i & k)
          str[j] = '1';
        else
          str[j] = '0';
        k<<=1;
      };

    str[RSBAC_RC_NR_ROLES] = 0;
    return (str);
  };

__u64 strtou64rc(char * str, __u64 * i_p)
  {
    int    j;
    __u64  k = 1, res=0;
    
    if(!str)
      return(0);

    if (strlen(str) < RSBAC_RC_NR_ROLES)
      return(-1);
    for(j=RSBAC_RC_MAX_ROLE;j>=0;j--)
      {
        if(str[j] != '0')
          {
            res |= k;
          }
        k <<= 1;
      }
    for(j=RSBAC_RC_NR_ROLES;j<64;j++)
      {
        res |= k;
        k <<= 1;
      }
    *i_p = res;
    return(res);
  };

char * u64tostrrcr(char * str, __u64 i)
  {
    int    j = 0;
    __u64  k;

    if(!str)
      return(NULL);

    k = 1;
    for(j = RCR_NONE - 1;j >= 0;j--)
      {
        if (i & k)
          str[j] = '1';
        else
          str[j] = '0';
        k<<=1;
      };

    str[RCR_NONE] = 0;
    return (str);
  };

__u64 strtou64rcr(char * str, __u64 * i_p)
  {
    int    j;
    __u64  k = 1, res=0;
    
    if(!str)
      return(0);

    if (strlen(str) < RCR_NONE)
      return(-1);
    for(j=RCR_NONE-1;j>=0;j--)
      {
        if(str[j] != '0')
          {
            res |= k;
          }
        k <<= 1;
      }
    for(j=RCR_NONE;j<64;j++)
      {
        res |= k;
        k <<= 1;
      }
    *i_p = res;
    return(res);
  };

char * u64tostrmac(char * str, __u64 i)
  {
    int    j = 0;
    __u64  k;

    if(!str)
      return(NULL);

    k = 1;
    for(j = RSBAC_MAC_MAX_CAT;j >= 0;j--)
      {
        if (i & k)
          str[j] = '1';
        else
          str[j] = '0';
        k<<=1;
      };

    str[RSBAC_MAC_NR_CATS] = 0;
    return (str);
  };

__u64 strtou64mac(char * str, __u64 * i_p)
  {
    int    j;
    __u64  k = 1, res=0;
    
    if(!str)
      return(0);

    if (strlen(str) < RSBAC_MAC_NR_CATS)
      return(-1);
    for(j=RSBAC_MAC_MAX_CAT;j>=0;j--)
      {
        if(str[j] != '0')
          {
            res |= k;
          }
        k <<= 1;
      }
    for(j=RSBAC_MAC_NR_CATS;j<64;j++)
      {
        res |= k;
        k <<= 1;
      }
    *i_p = res;
    return(res);
  };

__u64 strtou64acl(char * str, __u64 * i_p)
  {
    int    j;
    __u64  k = 1, res=0;
    
    if(!str)
      return(0);

    if (strlen(str) < (ACLR_NONE - 1))
      return(-1);
    for(j=ACLR_NONE-1;j>=0;j--)
      {
        if(str[j] != '0')
          {
            res |= k;
          }
        k <<= 1;
      }
    for(j=ACLR_NONE-1;j<64;j++)
      {
        res |= k;
        k <<= 1;
      }
    *i_p = res;
    return(res);
  };
#endif

char * u64tostracl(char * str, __u64 i)
  {
    int    j = 0;
    __u64  k;

    if(!str)
      return(NULL);

    k = 1;
    for(j = ACLR_NONE - 1;j >= 0;j--)
      {
        if (i & k)
          str[j] = '1';
        else
          str[j] = '0';
        k<<=1;
      };

    str[ACLR_NONE] = 0;
    return (str);
  };

#ifdef __KERNEL__

/* find the current owner of this process */
int rsbac_get_owner(rsbac_uid_t * user_p)
  {
#ifdef CONFIG_RSBAC_USE_RSBAC_OWNER
    union rsbac_target_id_t       i_tid;
    union rsbac_attribute_value_t i_attr_val1;
    int err;

    /* getting process owner from rsbac system */
    i_tid.process = caller_pid;
    err = rsbac_get_attr(T_PROCESS,i_tid,A_owner,&i_attr_val1,FALSE);
    if (err)
      {
        char * tmp = kmalloc(RSBAC_MAXNAMELEN, GFP_KERNEL);

        if(tmp)
          {
            printk(KERN_WARNING
                   "rsbac_get_owner(): rsbac_get_attr() for owner returned error %s",
                   get_error_name(tmp,err));
            kfree(tmp);
          }
        return(-RSBAC_EREADFAILED);  /* something weird happened */
      }
    *user_p = i_attr_val1.owner;
    if (*user_p == RSBAC_NO_USER)
      { /* This process has not been registered yet */
        /* -> use unix owner */
        *user_p = current->uid;
      }
    else
      *user_p = i_attr_val.owner;
#else /* CONFIG_RSBAC_USE_RSBAC_OWNER not set -> always use linux owner */
    *user_p = current->uid;
#endif /* CONFIG_RSBAC_USE_RSBAC_OWNER */
    return(0);
  }



/****************************************************************/
/* Access to user data space                                    */


#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_get_user);
#endif
int rsbac_get_user(unsigned char * kern_p, unsigned char * user_p, int size)
  {
    if(kern_p && user_p && (size > 0))
      {
        return copy_from_user(kern_p, user_p, size);
      }
    return(0);
  };


#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_put_user);
#endif
int rsbac_put_user(unsigned char * kern_p, unsigned char * user_p, int size)
  {
    if(kern_p && user_p && (size > 0))
      {
        return copy_to_user(user_p,kern_p,size);
      }
    return(0);
  };

#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_getname);
#endif
char * rsbac_getname(const char * name)
  {
    return getname(name);
  };

#ifdef CONFIG_RSBAC_REG
EXPORT_SYMBOL(rsbac_putname);
#endif
void rsbac_putname(const char * name)
  {
    putname(name);
  };

inline void clear_user_buf(char * ubuf, int len)
  {
    clear_user(ubuf,len);
  };

#endif /* __KERNEL__ */
