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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <rsbac/types.h>
#include <rsbac/rc_data_structures.h>
#include <rsbac/getname.h>
#include <rsbac/rc_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

/* reserve list room for so many extra items - to avoid racing problems */
#define LISTROOM 10

char * progname;

void use(void)
    {
        printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
        printf(gettext("Use: %s [switches] rc-target-type id item [role/type [list-of-rights]] [value]\n"), progname);  
        printf(gettext("     %s -c TYPE target-id item source-id [first_role [last_role]],\n"), progname);
        printf(gettext(" -h = this help, -- = no more flags,\n"));
        printf(gettext(" -v = verbose, -p = print right names,\n"));
        printf(gettext(" -a = add, not set, -k = revoke, not set,\n"));
        printf(gettext(" -b = accept rights as bitstring,\n"));
        printf(gettext(" -c = copy all/given roles' rights to type from other type,\n"));
        printf(gettext(" -d = delete all roles' rights to this type,\n"));
        printf(gettext(" -i = list items and values\n"));
        printf(gettext(" -t = set relative time-to-live in secs (role/type comp, admin, assign only)\n"));
        printf(gettext(" -T = set absolute time-to-live in secs (role/type comp, admin, assign only)\n"));
        printf(gettext(" -D = set relative time-to-live in days (role/type comp, admin, assign only)\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(" rc-target-type = ROLE or TYPE,\n"));
        printf(gettext(" id-nr = ROLE or TYPE number,\n"));
        printf(gettext(" item = entry line,\n"));
        printf(gettext(" role/type = for this type only (role/type comp, admin, assign only),\n"));
        printf(gettext(" right = request name or number (type_comp items only),\n"));
        printf(gettext("        also special rights and groups R (read requests),\n"));
        printf(gettext("        RW (read-write), SY (system), SE (security), A (all)\n"));
        exit(1);
    }

int mainloop(int argc, char ** argv)
{
  int res = 0;
  enum rsbac_adf_request_t right;
  rsbac_rc_rights_vector_t rights_vector = 0;
  rsbac_time_t ttl=RSBAC_LIST_TTL_KEEP;
  char tmp1[RSBAC_MAXNAMELEN],tmp2[RSBAC_MAXNAMELEN];
  int i,j;
  enum rsbac_rc_target_t target;
  union rsbac_rc_target_id_t tid;
  union rsbac_rc_target_id_t subtid;
  enum rsbac_rc_item_t item;
  union rsbac_rc_item_value_t value;
  int verbose=0;
  int printall=0;
  int add=0;
  int revoke=0;
  int bitstring=0;
  int copy=0;
  int delrights=0;
  rsbac_list_ta_number_t ta_number = 0;
  u_int stopflags = FALSE;

  progname = argv[0];
  locale_init();
  {
    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 'k':
                revoke=1;
                break;
              case 'b':
                bitstring=1;
                break;
              case 'c':
                copy=1;
                break;
              case 'd':
                delrights=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 'D':
                if(argc > 2)
                  {
                    ttl = 86400 * strtoul(argv[2], 0, 10);
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing ttl value for parameter %c\n"), progname, *pos);
                break;
              case 'T':
                if(argc > 2)
                  {
                    rsbac_time_t now = time(NULL);
                    ttl = strtoul(argv[2], 0, 10);
                    if(ttl > now)
                      {
                        ttl -= now;
                        argc--;
                        argv++;
                      }
                    else
                      {
                        fprintf(stderr,
                                gettext("%s: ttl value for parameter %c is in the past, exiting\n"), progname, *pos);
                        return __LINE__;
                      }
                  }
                else
                  fprintf(stderr, gettext("%s: missing ttl value for parameter %c\n"), progname, *pos);
                break;
              case 'i':
                {
                  int role_entry_item_list[RSBAC_RC_NR_ROLE_ENTRY_ITEMS] = RSBAC_RC_ROLE_ENTRY_ITEM_LIST;
                  int type_entry_item_list[RSBAC_RC_NR_TYPE_ENTRY_ITEMS] = RSBAC_RC_TYPE_ENTRY_ITEM_LIST;

                  if(   (argc > 2)
                     && ((item = get_rc_item_nr(argv[2])) != RI_none)
                    )
                    {
                      get_rc_item_name(tmp1, item);
                      get_rc_item_param(tmp2, item);
                      printf("%s\t%s\n",tmp1,tmp2);
                      return 0;
                    }
                  printf(gettext("- items and returned values = see following list:\n"));
                  printf("- ROLE:\n");
                  for (j=0;j<RSBAC_RC_NR_ROLE_ENTRY_ITEMS;j++)
                    {
                      get_rc_item_name(tmp1,role_entry_item_list[j]);
                      get_rc_item_param(tmp2,role_entry_item_list[j]);
                      printf("%s\t%s\n",tmp1,tmp2);
                    }
                  printf("remove_role\t\tRemove role, no value\n");
                  printf("\n- TYPE:\n");
                  for (j=0;j<RSBAC_RC_NR_TYPE_ENTRY_ITEMS;j++)
                    {
                      get_rc_item_name(tmp1,type_entry_item_list[j]);
                      get_rc_item_param(tmp2,type_entry_item_list[j]);
                      printf("%s\t%s\n",tmp1,tmp2);
                    }
                  for (j=RI_type_fd_remove;j<RI_none;j++)
                    {
                      get_rc_item_name(tmp1, j);
                      printf("%s  \tRemove type, no value\n",tmp1);
                    }
                  return 0;
                }
              case 'V':
                if(argc < 3)
                  {
                    fprintf(stderr, gettext("%s: no version number for switch V\n"), progname);
                    return __LINE__;
                  }
                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);
                    return __LINE__;
                  }
                break;

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

  if(argc < 4)
    {
      use();
      return __LINE__;
    }  

  target = get_rc_target_nr(argv[1]);
  switch(target)
    {
      case RT_ROLE:
        tid.role = strtol(argv[2],0,10);
        break;
      case RT_TYPE:
        tid.type = strtol(argv[2],0,10);
        break;
      default:
        fprintf(stderr, gettext("Invalid target %s\n"), argv[1]);
        return __LINE__;
    }
  item = get_rc_item_nr(argv[3]);
  if(item == RI_none)
    {
      fprintf(stderr, gettext("Invalid item %s\n"), argv[3]);
      return __LINE__;
    }

  if(copy)
    {
      rsbac_rc_type_id_t s_type;
      rsbac_rc_type_id_t t_type;
      rsbac_rc_role_id_t first_role = 0;
      rsbac_rc_role_id_t last_role = RC_role_max_value;
      union rsbac_rc_target_id_t t_subtid;
      __u32 * role_array;
      int nr_roles;
      int tmpres = 0;
      enum rsbac_rc_item_t item_log_always;
      enum rsbac_rc_item_t item_log_never;

      if(argc < 5)
        {
          fprintf(stderr, gettext("Too few arguments with option -c\n"));
          return __LINE__;
        }
      s_type = strtoul(argv[4],0,10);
      if(s_type > RC_type_max_value)
        {
          fprintf(stderr, gettext("Invalid source type %u\n"), s_type);
          return __LINE__;
        }
      if(argc > 5)
        {
          first_role = strtoul(argv[5],0,10);
          if(first_role > RC_role_max_value)
            {
              fprintf(stderr, gettext("Invalid first role %u\n"), first_role);
              return __LINE__;
            }
          last_role = first_role;
        }
      if(argc > 6)
        {
          last_role = strtoul(argv[6],0,10);
          if(last_role > RC_role_max_value)
            {
              fprintf(stderr, gettext("Invalid last role %u\n"), last_role);
              return __LINE__;
            }
        }
      t_type = tid.type;
      if(t_type > RC_type_max_value)
        {
          fprintf(stderr, gettext("Invalid target type %u\n"), t_type);
          return __LINE__;
        }
      if(s_type == t_type)
        {
          fprintf(stderr, gettext("Source and target must differ\n"));
          return __LINE__;
        }
      switch(item)
        {
          case RI_type_comp_fd:
          case RI_type_fd_name:
            item = RI_type_comp_fd;
            item_log_always = RI_type_comp_fd_log_always;
            item_log_never = RI_type_comp_fd_log_never;
            break;
          case RI_type_comp_dev:
          case RI_type_dev_name:
            item = RI_type_comp_dev;
            item_log_always = RI_type_comp_dev_log_always;
            item_log_never = RI_type_comp_dev_log_never;
            break;
          case RI_type_comp_user:
          case RI_type_user_name:
            item = RI_type_comp_user;
            item_log_always = RI_type_comp_user_log_always;
            item_log_never = RI_type_comp_user_log_never;
            break;
          case RI_type_comp_process:
          case RI_type_process_name:
            item = RI_type_comp_process;
            item_log_always = RI_type_comp_process_log_always;
            item_log_never = RI_type_comp_process_log_never;
            break;
          case RI_type_comp_ipc:
          case RI_type_ipc_name:
            item = RI_type_comp_ipc;
            item_log_always = RI_type_comp_ipc_log_always;
            item_log_never = RI_type_comp_ipc_log_never;
            break;
          case RI_type_comp_scd:
          case RI_type_scd_name:
            item = RI_type_comp_scd;
            item_log_always = RI_type_comp_scd_log_always;
            item_log_never = RI_type_comp_scd_log_never;
            break;
          case RI_type_comp_group:
          case RI_type_group_name:
            item = RI_type_comp_group;
            item_log_always = RI_type_comp_group_log_always;
            item_log_never = RI_type_comp_group_log_never;
            break;
          case RI_type_comp_netdev:
          case RI_type_netdev_name:
            item = RI_type_comp_netdev;
            item_log_always = RI_type_comp_netdev_log_always;
            item_log_never = RI_type_comp_netdev_log_never;
            break;
          case RI_type_comp_nettemp:
          case RI_type_nettemp_name:
            item = RI_type_comp_nettemp;
            item_log_always = RI_type_comp_nettemp_log_always;
            item_log_never = RI_type_comp_nettemp_log_never;
            break;
          case RI_type_comp_netobj:
          case RI_type_netobj_name:
            item = RI_type_comp_netobj;
            item_log_always = RI_type_comp_netobj_log_always;
            item_log_never = RI_type_comp_netobj_log_never;
            break;
          default:
            fprintf(stderr, gettext("Invalid item %s\n"), argv[3]);
            return __LINE__;
        }
      if(verbose)
        {
          printf(gettext("Copying rights vector %s for type %u to type %u in role(s) %u to %u\n"),
                 get_rc_item_name(tmp1, item),
                 s_type,
                 t_type,
                 first_role,
                 last_role);
        }
      subtid.type = s_type;
      t_subtid.type = t_type;
      nr_roles = rsbac_rc_get_list(ta_number, RT_ROLE, &tid, RI_name, 0, NULL, NULL);
      if (nr_roles < 0)
        return nr_roles;
      nr_roles += LISTROOM;
      role_array = malloc(nr_roles * sizeof(__u32));
      if(!role_array)
        {
          return -ENOMEM;
        }
      nr_roles = rsbac_rc_get_list(ta_number, RT_ROLE, &tid, RI_name, nr_roles, role_array, NULL);
      for(i=0; i<nr_roles; i++)
        {
          if(   (role_array[i] < first_role)
             || (role_array[i] > last_role)
            )
            continue;
          tid.role = role_array[i];
          if(!(tmpres = rsbac_rc_get_item(ta_number, RT_ROLE, &tid, &subtid, item, &value, &ttl)))
            {
              if((tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &t_subtid, item, &value, ttl)))
                {
                  fprintf(stderr, gettext("Changing role %u failed: %s\n"),
                          role_array[i],
                          get_error_name(tmp1, tmpres));
                  res = tmpres;
                }
            }
          else
            {
              if(errno != RSBAC_EINVALIDTARGET)
                {
                  fprintf(stderr, gettext("Reading from role %u failed: %s\n"),
                          role_array[i],
                          get_error_name(tmp1, tmpres));
                  res = tmpres;
                }
            }
          if(!(tmpres = rsbac_rc_get_item(ta_number, RT_ROLE, &tid, &subtid, item_log_always, &value, &ttl)))
            {
              if((tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &t_subtid, item_log_always, &value, ttl)))
                {
                  fprintf(stderr, gettext("Changing role %u log always failed: %s\n"),
                          role_array[i],
                          get_error_name(tmp1, tmpres));
                  res = tmpres;
                }
            }
          if(!(tmpres = rsbac_rc_get_item(ta_number, RT_ROLE, &tid, &subtid, item_log_never, &value, &ttl)))
            {
              if((tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &t_subtid, item_log_never, &value, ttl)))
                {
                  fprintf(stderr, gettext("Changing role %u log never failed: %s\n"),
                          role_array[i],
                          get_error_name(tmp1, tmpres));
                  res = tmpres;
                }
            }
        }
      free(role_array);
      return res;
    } /* end of type rights copy */

  if(delrights)
    {
      int tmpres = 0;
      rsbac_rc_type_id_t t_type;
      __u32 * role_array;
      int nr_roles;
      enum rsbac_rc_item_t item_log_always;
      enum rsbac_rc_item_t item_log_never;

      t_type = tid.type;
      if(t_type > RC_type_max_value)
        {
          fprintf(stderr, gettext("Invalid target type %u\n"), t_type);
          return __LINE__;
        }
      switch(item)
        {
          case RI_type_comp_fd:
          case RI_type_fd_name:
            item = RI_type_comp_fd;
            item_log_always = RI_type_comp_fd_log_always;
            item_log_never = RI_type_comp_fd_log_never;
            break;
          case RI_type_comp_dev:
          case RI_type_dev_name:
            item = RI_type_comp_dev;
            item_log_always = RI_type_comp_dev_log_always;
            item_log_never = RI_type_comp_dev_log_never;
            break;
          case RI_type_comp_user:
          case RI_type_user_name:
            item = RI_type_comp_user;
            item_log_always = RI_type_comp_user_log_always;
            item_log_never = RI_type_comp_user_log_never;
            break;
          case RI_type_comp_process:
          case RI_type_process_name:
            item = RI_type_comp_process;
            item_log_always = RI_type_comp_process_log_always;
            item_log_never = RI_type_comp_process_log_never;
            break;
          case RI_type_comp_ipc:
          case RI_type_ipc_name:
            item = RI_type_comp_ipc;
            item_log_always = RI_type_comp_ipc_log_always;
            item_log_never = RI_type_comp_ipc_log_never;
            break;
          case RI_type_comp_scd:
          case RI_type_scd_name:
            item = RI_type_comp_scd;
            item_log_always = RI_type_comp_scd_log_always;
            item_log_never = RI_type_comp_scd_log_never;
            break;
          case RI_type_comp_group:
          case RI_type_group_name:
            item = RI_type_comp_group;
            item_log_always = RI_type_comp_group_log_always;
            item_log_never = RI_type_comp_group_log_never;
            break;
          case RI_type_comp_netdev:
          case RI_type_netdev_name:
            item = RI_type_comp_netdev;
            item_log_always = RI_type_comp_netdev_log_always;
            item_log_never = RI_type_comp_netdev_log_never;
            break;
          case RI_type_comp_nettemp:
          case RI_type_nettemp_name:
            item = RI_type_comp_nettemp;
            item_log_always = RI_type_comp_nettemp_log_always;
            item_log_never = RI_type_comp_nettemp_log_never;
            break;
          case RI_type_comp_netobj:
          case RI_type_netobj_name:
            item = RI_type_comp_netobj;
            item_log_always = RI_type_comp_netobj_log_always;
            item_log_never = RI_type_comp_netobj_log_never;
            break;
          default:
            fprintf(stderr, gettext("Invalid item %s\n"), argv[3]);
            return __LINE__;
        }
      if(verbose)
        {
          printf(gettext("Setting rights vector %s for type %u in all roles to 0\n"),
                 get_rc_item_name(tmp1, item),
                 t_type);
        }
      subtid.type = t_type;
      value.rights = 0;
      nr_roles = rsbac_rc_get_list(ta_number, RT_ROLE, &tid, RI_name, 0, NULL, NULL);
      if (nr_roles < 0)
        return nr_roles;
      nr_roles += LISTROOM;
      role_array = malloc(nr_roles * sizeof(__u32));
      if(!role_array)
        {
          return -ENOMEM;
        }
      nr_roles = rsbac_rc_get_list(ta_number, RT_ROLE, &tid, RI_name, nr_roles, role_array, NULL);
      if(verbose)
        {
          printf(gettext("%u roles\n"),
                 nr_roles);
        }
      for(i=0; i<nr_roles; i++)
        {
          tid.role = role_array[i];
          if(   (tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &subtid, item, &value, 0))
             && (errno != RSBAC_ENOTFOUND)
            )
            {
              fprintf(stderr, gettext("Changing role %u failed: %s\n"),
                      role_array[i],
                      get_error_name(tmp1, tmpres));
              res = tmpres;
            }
          if(   (tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &subtid, item_log_always, &value, 0))
             && (errno != RSBAC_ENOTFOUND)
            )
            {
              fprintf(stderr, gettext("Changing role %u log always failed: %s\n"),
                      role_array[i],
                      get_error_name(tmp1, tmpres));
            }
          if(   (tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &subtid, item_log_never, &value, 0))
             && (errno != RSBAC_ENOTFOUND)
            )
            {
              fprintf(stderr, gettext("Changing role %u log never failed: %s\n"),
                      role_array[i],
                      get_error_name(tmp1, tmpres));
            }
        }
      return res;
    } /* end of set type rights to 0 */

  switch (item)
    {
      case RI_role_comp:
      case RI_admin_roles:
      case RI_assign_roles:
        if(   (argc == 5)
           && (strlen(argv[4]) == 64)
          )
          {
            rsbac_rc_role_vector_t rvec=0;
            int tmpres;

            strtou64rc(argv[4],&rvec);
            if(verbose)
              {
                printf(gettext("Setting %s of ROLE %i (old bitvector mode)\n"),
                       get_rc_item_name(tmp1, item), tid.role);
              }
            for (i=0; i<64; i++)
              {
                if(rvec & RSBAC_RC_ROLE_VECTOR(i))
                  {
                    if(printall)
                      {
                        printf("  %i to TRUE\n", i);
                      }
                    value.comp = TRUE;
                  }
                else
                  {
                    if(printall)
                      {
                        printf("  %i to FALSE\n", i);
                      }
                    value.comp = FALSE;
                  }
                subtid.role = i;
                if((tmpres = rsbac_rc_set_item(ta_number, RT_ROLE, &tid, &subtid, item, &value, ttl)))
                  {
                    fprintf(stderr, gettext("Setting for role %u failed: %s\n"),
                            i,
                            get_error_name(tmp1, tmpres));
                    res = tmpres;
                  }
              }
            return 0;
          }
        else
        if(argc==6)
          {
            subtid.role = strtoul(argv[4],0,10);
#if 0
            if(subtid.role > RC_role_max_value)
              {
                fprintf(stderr, gettext("Invalid role %u!\n"),
                        subtid.role);
                return __LINE__;
              }
#endif
            value.comp = strtol(argv[5],0,10);
            
          }
        else
          {
            fprintf(stderr, gettext("Invalid number of arguments for item %s!\n"),
                    get_rc_item_name(tmp1, item));
            return __LINE__;
          }
        break;

      case RI_def_fd_ind_create_type:
        if(argc==6)
          {
            subtid.type = strtoul(argv[4],0,10);
            if(subtid.type > RC_type_max_value)
              {
                fprintf(stderr, gettext("Invalid type %u!\n"),
                        subtid.type);
                return __LINE__;
              }
            value.type_id = strtoul(argv[5],0,10);
          }
        else
          {
            fprintf(stderr, gettext("Invalid number of arguments for item %s!\n"),
                    get_rc_item_name(tmp1, item));
            return __LINE__;
          }
        break;

      case RI_def_fd_ind_create_type_remove:
        if(argc==5)
          {
            subtid.type = strtoul(argv[4],0,10);
            if(subtid.type > RC_type_max_value)
              {
                fprintf(stderr, gettext("Invalid type %u!\n"),
                        subtid.type);
                return __LINE__;
              }
          }
        else
          {
            fprintf(stderr, gettext("Invalid number of arguments for item %s!\n"),
                    get_rc_item_name(tmp1, item));
            return __LINE__;
          }
        break;

      case RI_type_comp_fd:
      case RI_type_comp_dev:
      case RI_type_comp_user:
      case RI_type_comp_process:
      case RI_type_comp_ipc:
      case RI_type_comp_scd:
      case RI_type_comp_group:
      case RI_type_comp_netdev:
      case RI_type_comp_nettemp:
      case RI_type_comp_netobj:
      case RI_type_comp_fd_log_always:
      case RI_type_comp_dev_log_always:
      case RI_type_comp_user_log_always:
      case RI_type_comp_process_log_always:
      case RI_type_comp_ipc_log_always:
      case RI_type_comp_scd_log_always:
      case RI_type_comp_group_log_always:
      case RI_type_comp_netdev_log_always:
      case RI_type_comp_nettemp_log_always:
      case RI_type_comp_netobj_log_always:
      case RI_type_comp_fd_log_never:
      case RI_type_comp_dev_log_never:
      case RI_type_comp_user_log_never:
      case RI_type_comp_process_log_never:
      case RI_type_comp_ipc_log_never:
      case RI_type_comp_scd_log_never:
      case RI_type_comp_group_log_never:
      case RI_type_comp_netdev_log_never:
      case RI_type_comp_nettemp_log_never:
      case RI_type_comp_netobj_log_never:
        if(argc<5)
          {
            fprintf(stderr, gettext("parameter comp_type missing\n"));
            return __LINE__;
          }
        subtid.type = strtoul(argv[4],0,10);
        if(subtid.type > RC_type_max_value)
          {
            fprintf(stderr, gettext("invalid subtid.type %s\n"), argv[4]);
            return __LINE__;
          }
        if(add || revoke)
          res = rsbac_rc_get_item(ta_number, target, &tid, &subtid, item, &value, NULL);
        if (res < 0)
          return res;
        if(bitstring)
          {
            if(argc > 5)
              {
                if(strlen(argv[5]) != RCR_NONE)
                  {
                    fprintf(stderr, gettext("Invalid bitstring length %zu, must be %u!\n"),
                            strlen(argv[5]),
                            RCR_NONE);
                    return __LINE__;
                  }
              }
            else
              {
                fprintf(stderr, gettext("No bitstring given!\n"));
                return __LINE__;
              }
            strtou64rcr(argv[5], &rights_vector);
            argv++;
            argc--;
          }
        else
        for(i=5; i<argc; i++)
          {
            right = get_rc_special_right_nr(argv[i]);
            if((right == R_NONE) || (((enum rsbac_rc_special_rights_t) right) == RCR_NONE))
              {
                right = strtol(argv[i],0,10);
                if(   (   (right >= R_NONE)
                       && (right < RSBAC_RC_SPECIAL_RIGHT_BASE)
                      )
                   || (((enum rsbac_rc_special_rights_t) right) >= RCR_NONE)
                   || (   (right == 0)
                       && strcmp(argv[i],"0")
                      )
                  )
                  {
                    if(!strcmp(argv[i],"W"))
                      {
                        rights_vector |= RSBAC_WRITE_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"RW"))
                      {
                        rights_vector |= RSBAC_READ_WRITE_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"SY"))
                      {
                        rights_vector |= RSBAC_SYSTEM_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"SE"))
                      {
                        rights_vector |= RSBAC_SECURITY_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"S"))
                      {
                        rights_vector |= RSBAC_RC_SPECIAL_RIGHTS_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"R"))
                      {
                        rights_vector |= RSBAC_READ_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"UA"))
                      {
                        rights_vector &= RSBAC_RC_SPECIAL_RIGHTS_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"A"))
                      {
                        rights_vector |= RSBAC_ALL_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWS"))
                      {
                        rights_vector |= RSBAC_NWS_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWR"))
                      {
                        rights_vector |= RSBAC_NWR_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWW"))
                      {
                        rights_vector |= RSBAC_NWW_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWC"))
                      {
                        rights_vector |= RSBAC_NWC_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWE"))
                      {
                        rights_vector |= RSBAC_NWE_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWA"))
                      {
                        rights_vector |= RSBAC_NWA_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWF"))
                      {
                        rights_vector |= RSBAC_NWF_REQUEST_VECTOR;
                      }
                    else
                    if(!strcmp(argv[i],"NWM"))
                      {
                        rights_vector |= RSBAC_NWM_REQUEST_VECTOR;
                      }
                    else
                      { /* end of rights */
                        break;
                      }
                  }
              }
            else
              {
                rights_vector |= RSBAC_RC_RIGHTS_VECTOR(right);
              }
          }
        if(printall)
          {
            for (i=0; i<R_NONE; i++)
              if(rights_vector & RSBAC_RC_RIGHTS_VECTOR(i))
                printf("  %s\n", get_request_name(tmp1,i));
            for (i=RSBAC_RC_SPECIAL_RIGHT_BASE; i<RCR_NONE; i++)
              if(rights_vector & RSBAC_RC_RIGHTS_VECTOR(i))
                printf("  %s\n", get_rc_special_right_name(tmp1,i));
          }
        switch(item)
          {
            case RI_none:
              fprintf(stderr, gettext("Invalid item %s\n"), argv[3]);
              return __LINE__;
            case RI_type_comp_fd:
            case RI_type_comp_fd_log_always:
            case RI_type_comp_fd_log_never:
              rights_vector &= (RSBAC_FD_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_dev:
            case RI_type_comp_dev_log_always:
            case RI_type_comp_dev_log_never:
              rights_vector &= (RSBAC_DEV_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_user:
            case RI_type_comp_user_log_always:
            case RI_type_comp_user_log_never:
              rights_vector &= (RSBAC_USER_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_process:
            case RI_type_comp_process_log_always:
            case RI_type_comp_process_log_never:
              rights_vector &= (RSBAC_RC_PROCESS_RIGHTS_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_ipc:
            case RI_type_comp_ipc_log_always:
            case RI_type_comp_ipc_log_never:
              rights_vector &= (RSBAC_IPC_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_scd:
            case RI_type_comp_scd_log_always:
            case RI_type_comp_scd_log_never:
              rights_vector &= (RSBAC_SCD_REQUEST_VECTOR | RSBAC_NONE_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_group:
            case RI_type_comp_group_log_always:
            case RI_type_comp_group_log_never:
              rights_vector &= (RSBAC_GROUP_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_netdev:
            case RI_type_comp_netdev_log_always:
            case RI_type_comp_netdev_log_never:
              rights_vector &= (RSBAC_NETDEV_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_nettemp:
            case RI_type_comp_nettemp_log_always:
            case RI_type_comp_nettemp_log_never:
              rights_vector &= (RSBAC_NETTEMP_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            case RI_type_comp_netobj:
            case RI_type_comp_netobj_log_always:
            case RI_type_comp_netobj_log_never:
              rights_vector &= (RSBAC_NETOBJ_REQUEST_VECTOR | RSBAC_RC_SPECIAL_RIGHTS_VECTOR);
              break;
            default:
              rights_vector &= RSBAC_RC_ALL_RIGHTS_VECTOR;
          }
        if(add)
          {
            if(verbose)
              {
                printf(gettext("Adding %s rights for ROLE %u to TYPE %u\n"),
                       get_rc_item_name(tmp1, item), tid.role, subtid.type);
              }
            value.rights |= rights_vector;
          }
        else
        if(revoke)
          {
            if(verbose)
              {
                printf(gettext("Revoking %s rights for ROLE %u from TYPE %u\n"),
                       get_rc_item_name(tmp1, item), tid.role, subtid.type);
              }
            value.rights &= ~rights_vector;
          }
        else
          {
            if(verbose)
              {
                printf(gettext("Setting %s rights for ROLE %u to TYPE %u\n"),
                       get_rc_item_name(tmp1, item), tid.role, subtid.type);
              }
            value.rights = rights_vector;
          }
        if(printall)
          {
            for (i=0; i<R_NONE; i++)
              if(rights_vector & RSBAC_RC_RIGHTS_VECTOR(i))
                printf("  %s\n", get_request_name(tmp1,i));
            for (i=RSBAC_RC_SPECIAL_RIGHT_BASE; i<RCR_NONE; i++)
              if(rights_vector & RSBAC_RC_RIGHTS_VECTOR(i))
                printf("  %s\n", get_rc_special_right_name(tmp1,i));
          }
        break;

      case RI_name:
      case RI_type_fd_name:
      case RI_type_dev_name:
      case RI_type_ipc_name:
      case RI_type_user_name:
      case RI_type_process_name:
      case RI_type_group_name:
      case RI_type_netdev_name:
      case RI_type_nettemp_name:
      case RI_type_netobj_name:
        if(argc<5)
          {
            fprintf(stderr, gettext("parameter name missing\n"));
            return __LINE__;
          }
        if(strlen(argv[4]) >= RSBAC_RC_NAME_LEN)
          {
            fprintf(stderr, gettext("Name string \"%s\" too long, reducing to max len %u\n"), argv[4], RSBAC_RC_NAME_LEN - 1);
          }
        strncpy(value.name, argv[4], RSBAC_RC_NAME_LEN - 1);
        value.name[RSBAC_RC_NAME_LEN - 1] = 0;
        break;

      case RI_admin_type:
        if(argc<5)
          {
            fprintf(stderr, gettext("parameter admin_type missing\n"));
            return __LINE__;
          }
        value.admin_type = get_rc_admin_nr(argv[4]);
        if(value.admin_type == RC_none)
          value.admin_type = strtol(argv[4],0,10);
        break;

      case RI_boot_role:
        if(argc<5)
          {
            fprintf(stderr, gettext("parameter boot_role missing\n"));
            return __LINE__;
          }
        value.boot_role = strtol(argv[4],0,10);
        break;

      case RI_req_reauth:
	if(argc<5)
	{
		fprintf(stderr, gettext("parameter req_reauth missing\n"));
		return __LINE__;
	}
	value.req_reauth = strtol(argv[4],0,10);
	break;

      default:
        if(argc>4)
          value.u_dummy = strtoul(argv[4],0,10);
        else
          value.dummy = -1;
    }
  res = rsbac_rc_set_item(ta_number, target, &tid, &subtid, item, &value, ttl);
  return res;
}

#define MAXLINE 65536
#define MAXARGS 256

int main(int argc, char ** argv)
{
  char * line;
  int tmpargc;
  char ** tmpargv;
  int tmperr;
  char * p;
  char * tmpargp;
  int linenumber = 0;
  int inquotes;
  int verbose = 0;

/* classic call */
  if (argc <= 1 || strcmp(argv[1],"-"))
    exit(mainloop(argc, argv));

  if (argc > 2 && !strcmp(argv[2],"-v"))
    verbose = 1;

/* piped in backup script */
  line = (char *) malloc(MAXLINE);
  if (!line)
    error_exit(-RSBAC_ENOMEM);
  tmpargv = (char **) malloc(MAXARGS * sizeof(char *));
  if (!tmpargv) {
    free(line);
    error_exit(-RSBAC_ENOMEM);
  }

  while(fgets(line, MAXLINE, stdin)) {
    linenumber++;
    /* require line to start with rc_set_item */
    if (strncmp(line, "rc_set_item ", strlen("rc_set_item "))) {
      if (verbose)
        printf("Skipping line %u\n", linenumber);
      continue;
    }
    if (verbose)
      printf("Processing line %u:", linenumber);

    tmpargc = 0;
    p = line;
    inquotes = 0;
    while (*p && tmpargc < MAXARGS) {
      while (*p == ' ')
        p++;
      tmpargp = p;
      while (*p && *p != '\n' && (*p != ' ' || inquotes)) {
        if (*p == '"') {
          if (inquotes == 0)
            inquotes = 1;
          else
            inquotes = 0;
        }
        p++;
      }
      if (p > tmpargp) {
        *p = 0;
        if (*tmpargp == '"') {
          char * q;

          tmpargp++;
          q = tmpargp;
          while (*q && *q != '"')
            q++;
          if (*q)
            *q = 0;
        }
        tmpargv[tmpargc] = tmpargp;
        if (verbose)
          printf(" %s", tmpargv[tmpargc]);
        p++;
        tmpargc++;
      } else {
        break;
      }
    }
    if (tmpargc > 0) {
      if (verbose)
        printf("\n");
      tmperr = mainloop(tmpargc, tmpargv);
      if (tmperr) {
        if (tmperr < 0) {
          fprintf(stderr, "line %u: ", linenumber);
          show_error(tmperr);
        } else {
          fprintf(stderr, "line %u: error in program source line %u\n", linenumber, tmperr);
        }
      }
    }
  }

  free(line);
  free(tmpargv);
  return 0;
}
