#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rsbac/types.h>
#include <rsbac/aci_data_structures.h>
#include <rsbac/getname.h>
#include <rsbac/syscalls.h>
#include <rsbac/error.h>
#include <rsbac/helpers.h>

int main(int argc, char ** argv)
{
  enum rsbac_attribute_t attr_list[RSBAC_FD_NR_ATTRIBUTES] = RSBAC_FD_ATTR_LIST;
  enum rsbac_attribute_t attr_list_dev[RSBAC_DEV_NR_ATTRIBUTES] = RSBAC_DEV_ATTR_LIST;
  int res = 0;
  char tmp1[80],tmp2[120];
  int j;
  union rsbac_attribute_value_t value,value2;
  enum rsbac_target_t target;
  enum rsbac_attribute_t attr;
  enum rsbac_adf_request_t request;
  enum rsbac_log_level_t log_level;
  __u64 k;
  
  if (argc == 5)
    {
      target = get_target_nr(argv[1]);
      attr = get_attribute_nr(argv[3]);
      switch(attr)
        {
          case A_none:
            fprintf(stderr, "%s: Invalid attribute %s\n", argv[0], argv[3]);
            exit(1);
          case A_log_array_low:
          case A_log_array_high:
            if(strlen(argv[4]) != R_NONE)
              {
                fprintf(stderr, "%s: Invalid attribute value, length must be %i\n", argv[0], R_NONE);
                exit(1);
              }
            for(j=0;j<strlen(argv[4]);j++)
              {
                if(   argv[4][j] != '0'
                   && argv[4][j] != '1')
                  {
                    fprintf(stderr, "%s: Invalid attribute value char, must be 0 or 1\n", argv[0]);
                    exit(1);
                  }
              }
            strtou64log(argv[4], &value.log_array_low);
            break;

          case A_mac_trusted_for_user:
            value.mac_trusted_for_user = strtol(argv[4],0,0);

          default:
            value.dummy = strtol(argv[4],0,0);
        }
      res = rsbac_set_attr_n(target, argv[2], attr, &value);
      if(res)
        {
          if((res > -RSBAC_EPERM) || (res < -RSBAC_EDECISIONMISMATCH))
            {
              fprintf(stderr, "%s: Error: %s\n", argv[0], strerror(-res));
            }
          else
            {
              get_error_name(tmp1,res);
              fprintf(stderr, "%s: error: %s\n", argv[0], tmp1);
            }
          exit(1);
        }
      exit(0);
    }
  else
    if (   argc == 6
        && !strcmp(argv[3],"log_level"))
      {
        target = get_target_nr(argv[1]);
        request = get_request_nr(argv[4]);
        if(request == R_NONE)
          {
            fprintf(stderr, "Invalid request type %s\n", argv[4]);
            printf("Valid request types:\n");
            for(j=0;j<R_NONE;j++)
              {
                printf("%s\n", get_request_name(tmp1,j));
              }
            exit(1);
          }
        log_level = get_log_level_nr(argv[5]);
        if(log_level == LL_invalid)
          {
            log_level = strtol(argv[5],0,0);
            if(   (log_level >= LL_invalid)
               || (   (log_level == LL_none)
                   && strcmp(argv[5], "0")) )
              {
                fprintf(stderr, "Invalid log_level value %s\n", argv[5]);
                exit(1);
              }
          }
        res = rsbac_get_attr_n(target, argv[2], A_log_array_low, &value, FALSE);
        if(res)
          {
            if((res > -RSBAC_EPERM) || (res < -RSBAC_EDECISIONMISMATCH))
              {
                fprintf(stderr, "Get error: %s\n", strerror(-res));
              }
            else
              {
                get_error_name(tmp1,res);
                fprintf(stderr, "Get error: %s\n", tmp1);
              }
            exit(1);
          }
        res = rsbac_get_attr_n(target, argv[2], A_log_array_high, &value2, FALSE);
        if(res)
          {
            if((res > -RSBAC_EPERM) || (res < -RSBAC_EDECISIONMISMATCH))
              {
                fprintf(stderr, "Get error: %s\n", strerror(-res));
              }
            else
              {
                get_error_name(tmp1,res);
                fprintf(stderr, "Get error: %s\n", tmp1);
              }
            exit(1);
          }
        k=1;
        for(j=0; j<request; j++)
          k <<= 1;
        if(log_level & 1)
          value.log_array_low |= k;
        else
          value.log_array_low &= ~k;
        if(log_level & 2)
          value2.log_array_high |= k;
        else
          value2.log_array_high &= ~k;
        res = rsbac_set_attr_n(target, argv[2], A_log_array_low, &value);
        if(res)
          {
            if((res > -RSBAC_EPERM) || (res < -RSBAC_EDECISIONMISMATCH))
              {
                fprintf(stderr, "Set error: %s\n", strerror(-res));
              }
            else
              {
                get_error_name(tmp1,res);
                fprintf(stderr, "Set error: %s\n", tmp1);
              }
            exit(1);
          }
        res = rsbac_set_attr_n(target, argv[2], A_log_array_high, &value2);
        if(res)
          {
            if((res > -RSBAC_EPERM) || (res < -RSBAC_EDECISIONMISMATCH))
              {
                fprintf(stderr, "Set error: %s\n", strerror(-res));
              }
            else
              {
                get_error_name(tmp1,res);
                fprintf(stderr, "Set error: %s\n", tmp1);
              }
            exit(1);
          }
        exit(0);
      }
    else
      {
        printf("%s (RSBAC %s)\n***\n", argv[0], VERSION);
        printf("Use: %s target-type file/dirname attribute [request] value\n", argv[0]);  
        printf("- target-type = FILE, DIR or DEV,\n");
        printf("- attribute (string) and value (integer) = see following list:\n");
        printf("- FILE and DIR:\n");
        printf("log_level\t\t(additional parameter request-type)\n\t\t\t0=none, 1=denied, 2=full, 3=request\n");
        for (j=0;j<RSBAC_FD_NR_ATTRIBUTES;j++)
          {
            get_attribute_name(tmp1,attr_list[j]);
            get_attribute_param(tmp2,attr_list[j]);
            printf("%s \t%s\n",tmp1,tmp2);
          }
        printf("- DEV:\n");
        printf("log_level\t\t(additional parameter request-type)\n\t\t\t0=none, 1=denied, 2=full, 3=request based\n");
        for (j=0;j<RSBAC_DEV_NR_ATTRIBUTES;j++)
          {
            get_attribute_name(tmp1,attr_list_dev[j]);
            get_attribute_param(tmp2,attr_list_dev[j]);
            printf("%s \t%s\n",tmp1,tmp2);
          }
      }
  exit(1);
}
