/*************************************************** */
/* Rule Set Based Access Control                     */
/*                                                   */
/* Author and (c) 1999-2021: Amon Ott <ao@rsbac.org> */
/*                                                   */
/* Last modified: 24/Mar/2021                        */
/*************************************************** */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <rsbac/types.h>
#include <rsbac/aci_data_structures.h>
#include <rsbac/getname.h>
#include <rsbac/res_getname.h>
#include <rsbac/syscalls.h>
#include <rsbac/error.h>
#include <rsbac/helpers.h>
#include "nls.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define CAP_TO_INDEX(x)     ((x) >> 5)        /* 1 << 5 == bits in __u32 */

char * progname;

void use(void)
  {
    printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
    printf(gettext("Use: %s module target-type file/dirname attribute [request] value\n"), progname);  
    printf(gettext("Use: %s module target-type file/dirname attribute [position] value\n"), progname);  
    printf(gettext("Use: %s [switches] module target-type filename log_program_based [list-of-requests]\n"), progname);  
    printf(gettext(" -h = this help, -- = no more flags,\n"));
    printf(gettext(" -a = add, not set, -m = remove not set, -p = print resulting requests,\n"));
    printf(gettext(" -d = numeric device specification ({b|c}major[:minor])\n"));
    printf(gettext(" -t = rel. time-to-live in seconds, -T = absolute ttl since epoch\n"));
    printf(gettext(" -A = list attributes and values\n"));
    printf(gettext(" -V version = supply RSBAC integer version number for upgrading\n"));
    printf(gettext(" -N ta = transaction number (default = value of RSBAC_TA, if set, or 0)\n"));
    printf(gettext(" module = GEN, MAC, UDF, FF, RC, AUTH or RES\n"));
    printf(gettext(" target-type = FILE, DIR, FIFO, SYMLINK or DEV,\n"));
  }

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[RSBAC_MAXNAMELEN],tmp2[RSBAC_MAXNAMELEN],tmp3[RSBAC_MAXNAMELEN];
  int j;
  u_int position,catval;
  rsbac_res_limit_t res_limit;
  rsbac_boolean_t do_unset = FALSE;
  rsbac_time_t ttl = RSBAC_LIST_TTL_KEEP;
  union rsbac_attribute_value_t value,value2;
  enum rsbac_switch_target_t module = SW_NONE;
  enum rsbac_target_t target;
  union rsbac_target_id_t tid;
  enum rsbac_attribute_t attr;
  enum rsbac_log_level_t log_level;
  __u64 k;
  int verbose = 0;
  int printall = 0;
  int add = 0;
  int remove = 0;
  int numdev = 0;
  rsbac_list_ta_number_t ta_number = 0;
  u_int stopflags = FALSE;

  locale_init();

  progname = argv[0];
  {
    char * env = getenv("RSBAC_TA");

    if(env)
      ta_number = strtoul(env,0,0);
  }
  while((argc > 1) && (argv[1][0] == '-') && !stopflags)
    {
      char * pos = argv[1];
      pos++;
      while(*pos)
        {
          switch(*pos)
            {
              case '-':
                stopflags = TRUE;
                break;
              case 'h':
                use();
                return 0;
              case 'v':
                verbose++;
                break;
              case 'p':
                printall=1;
                break;
              case 'a':
                add=1;
                break;
              case 'm':
                remove=1;
                break;
              case 'd':
                numdev=1;
                break;
              case 't':
                if(argc > 2)
                  {
                    res = strtokmgu32(argv[2], &ttl);
                    error_exit(res);
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing ttl value for parameter %c\n"), progname, *pos);
                break;
              case 'T':
                if(argc > 2)
                  {
                    struct timeval now;
                    gettimeofday(&now, NULL);
                    ttl = strtoul(argv[2], 0, 10);
                    if (ttl <= now.tv_sec)
                      {
                        fprintf(stderr, gettext("%s: invalid ttl value for parameter %c\n"), progname, *pos);
                        exit(1);
                      }
                    ttl -= now.tv_sec;
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing ttl value for parameter %c\n"), progname, *pos);
                break;
              case 'n':
                {
                  char tmp[80];
                  int i;

                  for(i=0; i<R_NONE; i++)
                    printf("%s\n", get_request_name(tmp, i));
                  exit(0);
                }
              case 'A':
                if(   (argc > 2)
                   && ((attr = get_attribute_nr(argv[2])) != A_none)
                  )
                  {
                    get_switch_target_name(tmp1, get_attr_module(attr));
                    get_attribute_name(tmp2, attr);
                    get_attribute_param(tmp3, attr);
                    printf("[%-4s] %s\n\t%s\n",tmp1,tmp2,tmp3);
                    exit(0);
                  }
                printf(gettext("- attribute (string) and value (integer) = see following list:\n"));
                printf(gettext("[GEN ] log_level (additional parameter request-type)\n\t0=none, 1=denied, 2=full, 3=request-based\n"));
                printf(gettext("[GEN ] mac_categories (with additional parameter position)\n\t0=no, 1=yes\n"));
                printf(gettext("- FILE, DIR, FIFO and SYMLINK:\n"));
                for (j=0;j<RSBAC_FD_NR_ATTRIBUTES;j++)
                  {
                    get_switch_target_name(tmp1, get_attr_module(attr_list[j]));
                    get_attribute_name(tmp2,attr_list[j]);
                    get_attribute_param(tmp3,attr_list[j]);
                    printf("[%-4s] %s\n\t%s\n",tmp1,tmp2,tmp3);
                  }
                printf(gettext("[RES ] res_min|res_max (with additional parameter position)\n\tnon-negative integer (0 for unset)\n"));
                printf("- DEV:\n");
                for (j=0;j<RSBAC_DEV_NR_ATTRIBUTES;j++)
                  {
                    get_switch_target_name(tmp1, get_attr_module(attr_list_dev[j]));
                    get_attribute_name(tmp2,attr_list_dev[j]);
                    get_attribute_param(tmp3,attr_list_dev[j]);
                    printf("[%-4s] %s\n\t%s\n",tmp1,tmp2,tmp3);
                  }
                exit(0);
              case 'V':
                if(argc < 3)
                  {
                    fprintf(stderr, gettext("%s: no version number for switch V\n"), progname);
                    exit(1);
                  }
                argv++;
                argc--;
                break;
              case 'N':
                if(argc > 2)
                  {
                    ta_number = strtoul(argv[2], 0, 10);
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing transaction number value for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;

              default:
                fprintf(stderr, gettext("%s: unknown parameter %c\n"), progname, *pos);
                exit(1);
            }
          pos++;
        }
      argv++;
      argc--;
    }

  if(argc > 1)
    {
      module = get_switch_target_nr(argv[1]);
      if(module != SW_NONE)
        {
          argv++;
          argc--;
        }
    }
  if(   (argc>3)
     && !strcmp(argv[3],"log_program_based")
    )
    {
      char * filename = argv[2];
      rsbac_boolean_t rused = FALSE;
      rsbac_boolean_t wused = FALSE;
      enum rsbac_adf_request_t request;
      rsbac_request_vector_t request_vector = 0;

      target = get_target_nr(argv[1]);
      value.log_program_based = 0;
      argv+=3;
      argc-=3;
      if(numdev)
        error_exit(strtodevdesc(argv[2], &tid.dev));
      if(add || remove)
        {
          if(numdev)
            res = rsbac_get_attr(ta_number, module, target, &tid, A_log_program_based, &value, FALSE);
          else
            res = rsbac_get_attr_n(ta_number, module, target, filename, A_log_program_based, &value, FALSE);
          if(res)
            {
              fprintf(stderr, "%s: %s: ", progname, filename);
              error_exit(res);
            }
        }
      while(argc > 1)
        {
          if(strlen(argv[1]) == R_NONE)
            {
              int j;
              rsbac_request_vector_t tmp_rv;

              for(j=0; j<R_NONE; j++)
                if(   (argv[1][j] != '0')
                   && (argv[1][j] != '1')
                  )
                  {
                    fprintf(stderr, gettext("%s: Invalid request vector %s\n"), progname, argv[1]);
                    exit(1);
                  }
              strtou64acl(argv[1], &tmp_rv);
              request_vector |= tmp_rv;
              argv++;
              argc--;
              continue;
            }
          request = get_request_nr(argv[1]);
          if(request == R_NONE)
            {
              request = strtol(argv[1],0,10);
              if(   (request >= R_NONE)
                 || (   (request == 0)
                     && strcmp(argv[1],"0")
                    )
                )
                {
                  if(!strcmp(argv[1],"RW"))
                    {
                      request_vector |= RSBAC_READ_WRITE_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"SY"))
                    {
                      request_vector |= RSBAC_SYSTEM_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"SE"))
                    {
                      request_vector |= RSBAC_SECURITY_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"R"))
                    {
                      request_vector |= RSBAC_READ_REQUEST_VECTOR;
                      rused = TRUE;
                    }
                  else
                  if(!strcmp(argv[1],"W"))
                    {
                      request_vector |= RSBAC_WRITE_REQUEST_VECTOR;
                      wused = TRUE;
                    }
                  else
                  if(!strcmp(argv[1],"A"))
                    {
                      request_vector |= RSBAC_ALL_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"UA"))
                    {
                      request_vector = 0;
                    }
                  else
                  if(!strcmp(argv[1],"NWS"))
                    {
                      request_vector |= RSBAC_NWS_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"NWR"))
                    {
                      request_vector |= RSBAC_NWR_REQUEST_VECTOR;
                      rused = TRUE;
                    }
                  else
                  if(!strcmp(argv[1],"NWW"))
                    {
                      request_vector |= RSBAC_NWW_REQUEST_VECTOR;
                      wused = TRUE;
                    }
                  else
                  if(!strcmp(argv[1],"NWC"))
                    {
                      request_vector |= RSBAC_NWC_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"NWE"))
                    {
                      request_vector |= RSBAC_NWE_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"NWA"))
                    {
                      request_vector |= RSBAC_NWA_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"NWF"))
                    {
                      request_vector |= RSBAC_NWF_REQUEST_VECTOR;
                    }
                  else
                  if(!strcmp(argv[1],"NWM"))
                    {
                      request_vector |= RSBAC_NWM_REQUEST_VECTOR;
                    }
                  else
                    { /* end of requests */
                      break;
                    }
                }
            }
          else
            {
              request_vector |= ((rsbac_request_vector_t) 1 << request);
            }
          argv++;
          argc--;
        }
      if(rused && wused)
        {
          request_vector |= RSBAC_READ_WRITE_OPEN_REQUEST_VECTOR;
        }
      if(remove)
          value.log_program_based &= ~request_vector;
      else
          value.log_program_based |= request_vector;

      if(printall)
        {
          int i;

          for (i=0; i<R_NONE; i++)
            if(value.log_program_based & ((rsbac_request_vector_t) 1 << i))
              printf(" %s\n", get_request_name(tmp1,i));
        }
      if(numdev)
        res = rsbac_set_attr(ta_number, module, target, &tid, A_log_program_based, &value);
      else
        res = rsbac_set_attr_n(ta_number, module, target, filename, A_log_program_based, &value);
      if(res)
        {
          fprintf(stderr, "%s: %s: ", progname, filename);
          error_exit(res);
        }
      exit(0);
    }
  if(   (argc>3)
     && (   !strcmp(argv[3],"min_caps")
         || !strcmp(argv[3],"max_caps")
        )
    )
    {
      char * filename = argv[2];
      int cap;
      int bitlen;
      rsbac_cap_vector_t cap_vector;

      cap_vector.cap[0] = (__u32) 0;
      cap_vector.cap[1] = (__u32) 0;

      target = get_target_nr(argv[1]);
      attr = get_attribute_nr(argv[3]);
      value.min_caps.cap[0] = (__u32) 0;
      value.min_caps.cap[1] = (__u32) 0;
      argv+=3;
      argc-=3;
      if(add || remove)
        {
          res = rsbac_get_attr_n(ta_number, module, target, filename, attr, &value, FALSE);
          if(res)
            {
              fprintf(stderr, "%s: %s: ", progname, filename);
              error_exit(res);
            }
        }
      while(argc > 1)
        {
          /* Bit string: Allow for backwards compatibility */
          bitlen = strlen(argv[1]);
          if(bitlen == CAP_NONE || bitlen == CAP_NONE_OLD || bitlen == CAP_NONE_OLD_OLD)
            {
              int j;
              rsbac_cap_vector_t tmp_cv;

              for(j=0; j<bitlen; j++)
                if(   (argv[1][j] != '0')
                   && (argv[1][j] != '1')
                  )
                  {
                    fprintf(stderr, gettext("%s: Invalid cap vector %s\n"), progname, argv[1]);
                    exit(1);
                  }
              strcaptokcap(argv[1], &tmp_cv);
              cap_vector.cap[0] |= tmp_cv.cap[0];
	      cap_vector.cap[1] |= tmp_cv.cap[1];
              argv++;
              argc--;
              continue;
            }
          cap = get_cap_nr(argv[1]);
          if(cap == CAP_NONE)
            {
              cap = strtol(argv[1],0,10);
              if(   (cap >= CAP_NONE)
                 || (   (cap == 0)
                     && strcmp(argv[1],"0")
                    )
                )
                {
                  if(!strcmp(argv[1],"A"))
                    {
                      cap_vector.cap[0] = (__u32) -1;
		      cap_vector.cap[1] = (__u32) -1;
                    }
                  else
                  if(!strcmp(argv[1],"UA"))
                    {
                      cap_vector.cap[0] = (__u32) 0;
		      cap_vector.cap[1] = (__u32) 0;
                    }
                  else
                  if(!strcmp(argv[1],"FS_MASK"))
                    { /* one day we're going to have problem here.
			 it only works now because all that capabilities
			 in CAP_FS_MASK are in the lower (old) half
			 of capabilities structure. if someday a new fs cap
			 is added it's going to be in the upper (new) half
			 and we will have to put some logic in here.
			 CAP_TO_INDEX() macro will be necesary
			 - for all bits in this vector.
			 actualy, isn't FCAP such a one? */
                      cap_vector.cap[0] |= CAP_FS_MASK;
                    }
                  else
                    { /* end of caps */
                      fprintf(stderr, "%s: Wrong CAP %s\n", progname, argv[1]);
                      exit(1);
                    }
                }
              else
                {
                  fprintf(stderr, "%s: Wrong CAP %s\n", progname, argv[1]);
                  exit(1);
                }
            }
          else
            {
              cap_vector.cap[CAP_TO_INDEX(cap)] |= ((__u32) 1 << (cap % 32));
            }
          argv++;
          argc--;
        }
      if(remove) {
        value.min_caps.cap[0] &= ~cap_vector.cap[0];
        value.min_caps.cap[1] &= ~cap_vector.cap[1];
      } else {
        value.min_caps.cap[0] |= cap_vector.cap[0];
        value.min_caps.cap[1] |= cap_vector.cap[1];
      }

      if(printall)
        {
          int i;

          for (i=0; i<CAP_NONE; i++)
            if((value.min_caps.cap[0] & ((__u32) 1 << i)) || (value.min_caps.cap[1] & ((__u32) 1 << i)))
              printf(" %s\n", get_cap_name(tmp1,i));
        }
      res = rsbac_set_attr_n(ta_number, module, target, filename, attr, &value);
      if(res)
        {
          fprintf(stderr, "%s: %s: ", progname, filename);
          error_exit(res);
        }
      exit(0);
    }

  switch(argc)
    {
      case 5:
        target = get_target_nr(argv[1]);
        if(numdev)
          error_exit(strtodevdesc(argv[2], &tid.dev));
        attr = get_attribute_nr(argv[3]);
        switch(attr)
          {
            case A_none:
              fprintf(stderr, gettext("%s: Invalid attribute %s\n"), progname, argv[3]);
              exit(1);
            case A_res_min:
            case A_res_max:
              fprintf(stderr, gettext("%s: Invalid number of arguments for attribute %s\n"), progname, argv[3]);
              exit(1);
            case A_log_array_low:
            case A_log_array_high:
            case A_log_program_based:
              if(strlen(argv[4]) != R_NONE)
                {
                  fprintf(stderr, gettext("%s: Invalid attribute value, length must be %i\n"),
                                  progname, R_NONE);
                  exit(1);
                }
              for(j=0;j<strlen(argv[4]);j++)
                {
                  if(   argv[4][j] != '0'
                     && argv[4][j] != '1')
                    {
                      fprintf(stderr, gettext("%s: Invalid attribute value char, must be 0 or 1\n"), progname);
                      exit(1);
                    }
                }
              if(add || remove)
                {
                  rsbac_log_array_t newval;

                  if(numdev)
                    res = rsbac_get_attr(ta_number, module, target, &tid, attr, &value, FALSE);
                  else
                    res = rsbac_get_attr_n(ta_number, module, target, argv[2], attr, &value, FALSE);
                  if(res)
                    {
                      fprintf(stderr, "%s: %s: ", progname, argv[2]);
                      error_exit(res);
                    }
                  strtou64log(argv[4], &newval);
                  if(add)
                    value.log_array_low |= newval;
                  else
                    value.log_array_low &= ~newval;
                }
              else
                strtou64log(argv[4], &value.log_array_low);
              break;

            case A_security_level:
              value.security_level = strtoul(argv[4],0,10);
              break;

            case A_mac_categories:
              if(strlen(argv[4]) == RSBAC_MAC_NR_CATS)
                {
                  for(j=0;j<strlen(argv[4]);j++)
                    {
                      if(   argv[4][j] != '0'
                         && argv[4][j] != '1')
                        {
                          fprintf(stderr, gettext("%s: Invalid attribute value char, must be 0 or 1\n"), progname);
                          exit(1);
                        }
                    }
                  if(add || remove)
                    {
                      rsbac_mac_category_vector_t newval;

                      if(numdev)
                        res = rsbac_get_attr(ta_number, module, target, &tid, A_mac_categories, &value, FALSE);
                      else
                        res = rsbac_get_attr_n(ta_number, module, target, argv[2], A_mac_categories, &value, FALSE);
                      if(res)
                        {
                          fprintf(stderr, "%s: %s: ", progname, argv[2]);
                          error_exit(res);
                        }
                      strtou64mac(argv[4], &newval);
                      if(add)
                        value.mac_categories |= newval;
                      else
                        value.mac_categories &= ~newval;
                    }
                  else
                    strtou64mac(argv[4], &value.mac_categories);
                }
              else
                {
                  if(add || remove)
                    {
                      rsbac_mac_category_vector_t newval;

                      if(numdev)
                        res = rsbac_get_attr(ta_number, module, target, &tid, A_mac_categories, &value, FALSE);
                      else
                        res = rsbac_get_attr_n(ta_number, module, target, argv[2], A_mac_categories, &value, FALSE);
                      if(res)
                        {
                          fprintf(stderr, "%s: %s: ", progname, argv[2]);
                          error_exit(res);
                        }
                      newval = strtoul(argv[4], 0, 10);
                      if(add)
                        value.mac_categories |= newval;
                      else
                        value.mac_categories &= ~newval;
                    }
                  else
                    value.mac_categories = strtoul(argv[4], 0, 10);
                }
              break;

            case A_mac_auto:
              value.mac_auto = strtoul(argv[4],0,10);
              break;

            case A_mac_check:
              value.mac_check = strtoul(argv[4],0,10);
              break;

            case A_mac_prop_trusted:
              value.mac_prop_trusted = strtoul(argv[4],0,10);
              break;

            case A_mac_file_flags:
              if(add || remove)
                {
                  res = rsbac_get_attr_n(ta_number, module, target, argv[2], A_mac_file_flags, &value, FALSE);
                  if(res)
                    {
                      fprintf(stderr, "%s: %s: ", progname, argv[2]);
                      error_exit(res);
                    }
                  if(add)
                    value.mac_file_flags |= strtoul(argv[4],0,10);
                  else
                    value.mac_file_flags &= ~strtoul(argv[4],0,10);
                }
              else
                value.mac_file_flags = strtoul(argv[4],0,10);
              break;

            case A_udf_checker:
              value.udf_checker = strtoul(argv[4],0,10);
              break;

            case A_ff_flags:
              value.ff_flags = strtoul(argv[4],0,10);
              break;

            case A_rc_type:
            case A_rc_type_fd:
              value.rc_type = strtoul(argv[4],0,10);
              break;

            case A_rc_force_role:
            case A_rc_initial_role:
            case A_rc_role:
            case A_rc_def_role:
              value.rc_role = strtoul(argv[4],0,10);
              break;

            case A_auth_may_setuid:
              value.auth_may_setuid = strtoul(argv[4],0,10);
              break;

            case A_auth_may_set_cap:
              value.auth_may_set_cap = strtoul(argv[4],0,10);
              break;

            case A_auth_learn:
              value.auth_learn = strtoul(argv[4],0,10);
              break;

            case A_symlink_add_uid:
              value.symlink_add_uid = strtoul(argv[4],0,10);
              break;

            case A_symlink_add_mac_level:
              value.symlink_add_mac_level = strtoul(argv[4],0,10);
              break;

            case A_symlink_add_rc_role:
              value.symlink_add_rc_role = strtoul(argv[4],0,10);
              break;

            case A_allow_write_exec:
              value.allow_write_exec = strtoul(argv[4],0,10);
              break;

/*            case A_min_caps:
              value.min_caps = strtoul(argv[4],0,10);
              break;

            case A_max_caps:
              value.max_caps = strtoul(argv[4],0,10);
              break;*/

            case A_fake_root_uid:
              value.fake_root_uid = strtoul(argv[4],0,10);
              break;

            case A_auid_exempt:
              value.auid_exempt = strtoul(argv[4],0,10);
              break;

            default:
              value.dummy = strtol(argv[4],0,10);
          }
        if(verbose)
          {
            printf(gettext("Setting attribute %s for %s to value %lu\n"),
                   get_attribute_name(tmp1,attr),
                   argv[2],
                   value.u_long_dummy);
          }
        if(numdev)
          res = rsbac_set_attr(ta_number, module, target, &tid, attr, &value);
        else
          res = rsbac_set_attr_n(ta_number, module, target, argv[2], attr, &value);
        if(res)
          {
            fprintf(stderr, "%s: %s: ", progname, argv[2]);
            error_exit(res);
          }
        exit(0);

      case 6:
        if(numdev)
          error_exit(strtodevdesc(argv[2], &tid.dev));
        if(!strcmp(argv[3],"log_level"))
          {
            enum rsbac_adf_request_t request;

            target = get_target_nr(argv[1]);
            request = get_request_nr(argv[4]);
            if(request == R_NONE)
              {
                fprintf(stderr, gettext("Invalid request type %s\n"), argv[4]);
                printf(gettext("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,10);
                if(   (log_level >= LL_invalid)
                   || (   (log_level == LL_none)
                       && strcmp(argv[5], "0")) )
                  {
                    fprintf(stderr, gettext("Invalid log_level value %s\n"), argv[5]);
                    exit(1);
                  }
              }
            if(numdev)
              res = rsbac_get_attr(ta_number, module, target, &tid, A_log_array_low, &value, FALSE);
            else
              res = rsbac_get_attr_n(ta_number, module, target, argv[2], A_log_array_low, &value, FALSE);
            if(res)
              {
                fprintf(stderr, "%s: %s: ", progname, argv[2]);
                error_exit(res);
              }
            if(numdev)
              res = rsbac_get_attr(ta_number, module, target, &tid, A_log_array_high, &value2, FALSE);
            else
              res = rsbac_get_attr_n(ta_number, module, target, argv[2], A_log_array_high, &value2, FALSE);
            if(res)
              {
                fprintf(stderr, "%s: %s: ", progname, argv[2]);
                error_exit(res);
              }
            k = ((__u64) 1) << request;
            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;
            if(numdev)
              res = rsbac_set_attr(ta_number, module, target, &tid, A_log_array_low, &value);
            else
              res = rsbac_set_attr_n(ta_number, module, target, argv[2], A_log_array_low, &value);
            if(res)
              {
                fprintf(stderr, "%s: %s: ", progname, argv[2]);
                error_exit(res);
              }
            if(numdev)
              res = rsbac_set_attr(ta_number, module, target, &tid, A_log_array_high, &value2);
            else
              res = rsbac_set_attr_n(ta_number, module, target, argv[2], A_log_array_high, &value2);
            if(res)
              {
                fprintf(stderr, "%s: %s: ", progname, argv[2]);
                error_exit(res);
              }
            exit(0);
          }
        else
        if(!strcmp(argv[3],"mac_categories"))
          {
            target = get_target_nr(argv[1]);
            position = strtol(argv[4],0,10);
            if(position > RSBAC_MAC_MAX_CAT)
              {
                fprintf(stderr, gettext("Invalid position counter %s\n"), argv[4]);
                exit(1);
              }
            catval = strtol(argv[5],0,10);
            if(catval > 1)
              {
                fprintf(stderr, gettext("Invalid value %s\n"), argv[5]);
                exit(1);
              }
            if(numdev)
              res = rsbac_get_attr(ta_number, module, target, &tid, A_mac_categories, &value, FALSE);
            else
              res = rsbac_get_attr_n(ta_number, module, target, argv[2], A_mac_categories, &value, FALSE);
            if(res)
              {
                fprintf(stderr, "%s: %s: ", progname, argv[2]);
                error_exit(res);
              }
            k = ((__u64) 1) << position;
            if(catval)
              value.mac_categories |= k;
            else
              value.mac_categories &= ~k;
            if(numdev)
              res = rsbac_set_attr(ta_number, module, target, &tid, A_mac_categories, &value);
            else
              res = rsbac_set_attr_n(ta_number, module, target, argv[2], A_mac_categories, &value);
            if(res)
              {
                fprintf(stderr, "%s: %s: ", progname, argv[2]);
                error_exit(res);
              }
            exit(0);
          }
        else
        if(   !strcmp(argv[3],"res_min")
           || !strcmp(argv[3],"res_max")
          )
          {
            target = get_target_nr(argv[1]);
            position = get_res_nr(argv[4]);
            if(position == RSBAC_RES_NONE)
              {
                position = strtol(argv[4],0,10);
                if(   (!position && strcmp(argv[4], "0"))
                   || (position > RSBAC_RES_MAX)
                  )
                  {
                    fprintf(stderr, gettext("Invalid position counter %s\n"), argv[4]);
                    exit(1);
                  }
              }
            if(!strcmp(argv[5],"unset") || !strcmp(argv[5],"u"))
              {
                res_limit = 0;
                do_unset = TRUE;
              }
            else
              {
                res = strtokmgu64(argv[5], &res_limit);
                error_exit(res);
              }
            if(!strcmp(argv[3],"res_min"))
              attr = A_res_min;
            else
              attr = A_res_max;

            if (do_unset)
              res = rsbac_res_set_file_limit(ta_number, argv[2], attr, position, NULL, ttl);
            else
              res = rsbac_res_set_file_limit(ta_number, argv[2], attr, position, &res_limit, ttl);
            if(   ((res == -1) && (errno == RSBAC_EINVALIDREQUEST))
               || (res == -RSBAC_EINVALIDREQUEST)
              )
              {
                if(position > RSBAC_RES_MAX)
                  {
                    fprintf(stderr, gettext("Invalid position counter %s\n"), argv[4]);
                    exit(1);
                  }
                res = rsbac_get_attr_n(ta_number, module, target, argv[2], attr, &value, FALSE);
                if(res)
                  {
                    fprintf(stderr, "%s: %s: ", progname, argv[2]);
                    error_exit(res);
                  }
                value.res_array[position] = res_limit;
                res = rsbac_set_attr_n(ta_number, module, target, argv[2], attr, &value);
                if(res)
                  {
                    fprintf(stderr, "%s: %s: ", progname, argv[2]);
                    error_exit(res);
                  }
              }
            error_exit(res);
            exit(0);
          }

      default:
        use();
        return 1;
      }
  exit(1);
}
