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

#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>
#include "nls.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define ROOM 20

char * progname;

void use(void)
  {
    int j;
    char tmp1[RSBAC_MAXNAMELEN];
    char tmp2[RSBAC_MAXNAMELEN];
    int attr_list[RSBAC_IPC_NR_ATTRIBUTES] = RSBAC_IPC_ATTR_LIST;

    printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
    printf(gettext("Use: %s [flags] module ipc-type id attribute\n"),
           progname);  
    printf(gettext(" -N ta = transaction number (default = value of RSBAC_TA, if set, or 0)\n"));
    printf(gettext(" -i = list all IPC ids with non-default attributes\n"));
    printf(gettext(" ipc-types: sem, msg, shm, anonpipe, anonunix\n"));
    printf(gettext(" attribute (string) and returned value = see following list:\n"));
    for (j=0;j<RSBAC_IPC_NR_ATTRIBUTES;j++)
      {
        get_attribute_name(tmp1,attr_list[j]);
        get_attribute_param(tmp2,attr_list[j]);
        printf("%s \t%s\n",tmp1,tmp2);
      }
  }

int main(int argc, char ** argv)
{
  int res;
  u_int position;
  int i;
  char tmp2[RSBAC_MAXNAMELEN];
  enum rsbac_switch_target_t module = SW_NONE;
  union rsbac_attribute_value_t value;
  union rsbac_target_id_t tid;
  enum rsbac_ipc_type_t ipc_target;
  enum rsbac_attribute_t attr;
  rsbac_list_ta_number_t ta_number = 0;

  progname = argv[0];
  locale_init();

  {
    char * env = getenv("RSBAC_TA");

    if(env)
      ta_number = strtoul(env,0,0);
  }

  while((argc > 1) && (argv[1][0] == '-'))
    {
      char * pos = argv[1];
      pos++;
      while(*pos)
        {
          switch(*pos)
            {
              case 'h':
                use();
                return 0;
              case 'i':
                {
                  int count;
                  struct rsbac_ipc_t * id_array;
		  char tmp[RSBAC_MAXNAMELEN];

                  count = rsbac_list_all_ipc(ta_number, NULL, 0);
                  error_exit(count);
                  count += ROOM;
                  id_array = malloc(count * sizeof(*id_array));
                  if(!id_array)
                    error_exit(-ENOMEM);
                  count = rsbac_list_all_ipc(ta_number, id_array, count);
                  if(count > 0)
                    {
                      qsort(id_array, count, sizeof(*id_array), rsbac_user_compare);
                      for(i=0; i < count ; i++)
                        {
                          printf("%s %lu\n",
				get_ipc_target_name(tmp, id_array[i].type),
				id_array[i].id.id_nr);
                        }
                    }
                  free(id_array);
                }
                return 0;
              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 == 5) || (argc == 6))
     && (!strcmp(argv[3],"mac_categories")))
    {
      if((ipc_target = get_ipc_target_nr(argv[1])) == I_none)
        {
          fprintf(stderr, gettext("%s: Invalid IPC type %s!\n"), progname, argv[1]);
          exit(1);
        }
      tid.ipc.type = ipc_target;
      tid.ipc.id.id_nr = strtol(argv[2],0,10);

/*      value.dummy = -1; */
      position = strtol(argv[3],0,10);
      if(position > RSBAC_MAC_MAX_CAT)
        {
          fprintf(stderr, gettext("Invalid position counter %s\n"), argv[3]);
          exit(1);
        }
      res = rsbac_get_attr(ta_number, module, T_IPC, &tid, A_mac_categories, &value, 0);
      error_exit(res);
      printf("%u\n",
             (u_int) (value.mac_categories >> position) & 1);
      exit(0);
    }

  if ((argc == 4)||(argc == 5))
    {
      if((ipc_target = get_ipc_target_nr(argv[1])) == I_none)
        {
          fprintf(stderr, gettext("%s: Invalid IPC type %s!\n"), progname, argv[1]);
          exit(1);
        }
      tid.ipc.type = ipc_target;
      tid.ipc.id.id_nr = strtol(argv[2],0,10);

      attr = get_attribute_nr(argv[3]);
      if(attr == A_none)
        {
          fprintf(stderr, gettext("%s: Invalid Attribute %s!\n"), tmp2, argv[3]);
          exit(1);
        }
/*      value.dummy = -1; */
      res = rsbac_get_attr(ta_number, module, T_IPC, &tid, attr, &value, 0);
      error_exit(res);
      switch(attr)
        {
          case A_rc_type:
          case A_rc_type_fd:
          case A_rc_force_role:
          case A_rc_role:
          case A_rc_def_role:
            printf("%u\n",value.rc_type);
            break;
          case A_security_level:
            printf("%u\n",value.u_char_dummy);
            break;
          default:
            printf("%i\n",value.dummy);
        }
      exit(0);
    }

  use();
  exit(1);
}
