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

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

char * progname;

void use(void)
    {
      printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
      printf(gettext("Use: %s [switches] module target-type attribute value user/proc-nr.\n\n"), progname);  
      printf(gettext(" module = GEN, MAC, FC, SIM, PM, MS, FF, RC or AUTH\n"));
      printf(gettext(" target-type = USER or PROCESS\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"));
    }

int main(int argc, char ** argv)
{
  int res = 0;
  char tmp1[RSBAC_MAXNAMELEN],tmp2[RSBAC_MAXNAMELEN],tmp3[RSBAC_MAXNAMELEN];
  int i;
  int id;
  enum rsbac_switch_target_t module = SW_NONE;
  union rsbac_attribute_value_t value;
  enum rsbac_target_t target;
  union rsbac_target_id_t tid;
  enum rsbac_attribute_t attr;
  int verbose = 0;
  rsbac_version_t version=RSBAC_VERSION_NR;
  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 'v':
                verbose++;
                break;
              case 'a':
              case 'A':
                {
                  int u_attr_list[RSBAC_USER_NR_ATTRIBUTES] = RSBAC_USER_ATTR_LIST;
                  int p_attr_list[RSBAC_PROCESS_NR_ATTRIBUTES] = RSBAC_PROCESS_ATTR_LIST;

                  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("USER:\n");
                  for (i=0;i<RSBAC_USER_NR_ATTRIBUTES;i++)
                    {
                      get_switch_target_name(tmp1, get_attr_module(u_attr_list[i]));
                      get_attribute_name(tmp2,u_attr_list[i]);
                      get_attribute_param(tmp3,u_attr_list[i]);
                      printf("[%-4s] %s\n\t%s\n",tmp1,tmp2,tmp3);
                    }
                  printf("\nPROCESS:\n");
                  for (i=0;i<RSBAC_PROCESS_NR_ATTRIBUTES;i++)
                    {
                      get_switch_target_name(tmp1, get_attr_module(p_attr_list[i]));
                      get_attribute_name(tmp2,p_attr_list[i]);
                      get_attribute_param(tmp3,p_attr_list[i]);
                      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);
                  }
                version = strtol(argv[2],0,10);
                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 > 4)
    {
      printf(gettext("%s: %i targets\n\n"), progname, argc - 4);
      target = get_target_nr(argv[1]);
      if(   (target != T_PROCESS)
         && (target != T_USER))
        {
          fprintf(stderr, gettext("%s: Invalid Target %s!\n"), progname, argv[1]);
          exit(1);
        }
      attr = get_attribute_nr(argv[2]);
        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_security_level:
            case A_current_sec_level:
            case A_initial_security_level:
            case A_min_security_level:
            case A_min_write_open:
            case A_max_read_open:
              value.security_level = strtoul(argv[3],0,10);
              break;
            case A_mac_categories:
            case A_mac_initial_categories:
            case A_mac_min_categories:
            case A_mac_curr_categories:
            case A_min_write_categories:
            case A_max_read_categories:
              if(strlen(argv[3]) != RSBAC_MAC_NR_CATS)
                {
                  fprintf(stderr, gettext("%s: Invalid attribute value, length must be %i\n"), progname,
                          RSBAC_MAC_NR_CATS);
                  exit(1);
                }
              strtou64mac(argv[3], &value.mac_categories);
              break;
            case A_mac_user_flags:
              value.mac_user_flags = strtoul(argv[3],0,10);
              break;
            case A_mac_process_flags:
              value.mac_process_flags = strtoul(argv[3],0,10);
              break;
            case A_pseudo:
              value.pseudo = strtoul(argv[3],0,10);
              break;
            case A_log_user_based:
              value.log_user_based = strtoul(argv[3],0,10);
              break;
            case A_system_role:
            case A_mac_role:
            case A_daz_role:
            case A_ff_role:
            case A_auth_role:
            case A_cap_role:
            case A_jail_role:
            case A_res_role:
            case A_pax_role:
              value.system_role = strtoul(argv[3],0,10);
              break;
            case A_pm_role:
              value.pm_role = strtoul(argv[3],0,10);
              break;
            case A_pm_tp:
              value.pm_tp = strtoul(argv[3],0,10);
              break;
            case A_pm_task_set:
              value.pm_task_set = strtoul(argv[3],0,10);
              break;
            case A_pm_current_task:
              value.pm_current_task = strtoul(argv[3],0,10);
              break;
            case A_pm_process_type:
              value.pm_process_type = strtoul(argv[3],0,10);
              break;
            case A_daz_scanner:
              value.daz_scanner = strtoul(argv[3],0,10);
              break;
            case A_rc_def_role:
            case A_rc_role:
            case A_rc_force_role:
              value.rc_role = strtoul(argv[3],0,10);
              break;
            case A_rc_type:
              value.rc_type = strtoul(argv[3],0,10);
              break;
            case A_auth_may_setuid:
              value.auth_may_setuid = strtoul(argv[3],0,10);
              break;
            case A_auth_may_set_cap:
              value.auth_may_set_cap = strtoul(argv[3],0,10);
              break;
            case A_auth_learn:
              value.auth_learn = strtoul(argv[3],0,10);
              break;
            case A_cap_process_hiding:
              value.cap_process_hiding = strtoul(argv[3],0,10);
              break;
/*            case A_min_caps:
              value.min_caps = strtoul(argv[3],0,10);
              break;
            case A_max_caps:
            case A_max_caps_user:
            case A_max_caps_program:
              value.max_caps = strtoul(argv[3],0,10);
              break;*/
            case A_jail_id:
              value.jail_id = strtoul(argv[3],0,10);
              break;
            case A_jail_ip:
              value.jail_ip = strtoul(argv[3],0,10);
              break;
            case A_jail_flags:
              value.jail_flags = strtoul(argv[3],0,10);
              break;
/*            case A_jail_max_caps:
              value.jail_max_caps = strtoul(argv[3],0,10);
              break;*/
            case A_fake_root_uid:
              value.fake_root_uid = strtoul(argv[3],0,10);
              break;
            case A_audit_uid:
              value.audit_uid = strtoul(argv[3],0,10);
              break;
            case A_auid_exempt:
              value.auid_exempt = strtoul(argv[3],0,10);
              break;
            case A_auth_last_auth:
              value.auth_last_auth = strtoul(argv[3],0,10);
              break;

            default:
              value.dummy = strtoul(argv[3],0,10);
          }
      for (i=1;i < (argc-3);i++)
        {
          if (target == T_PROCESS)
            {
              id = strtol(argv[i+3],0,10);
              printf(gettext("Processing process %i, attribute %s (No. %u), value %i\n"), id, argv[2], attr, value.dummy);
              tid.process = id;
            }
          else
            {
              if(rsbac_get_uid(ta_number, &tid.user, argv[i+3]))
                {
                  fprintf(stderr, "Invalid User %s!\n\n", argv[i+3]);
                  continue;
                }
              if (RSBAC_UID_SET(tid.user))
                printf(gettext("Processing user %s (uid %u/%u), attribute %s (No. %u), value %i\n"),
                       argv[i+3], RSBAC_UID_SET(tid.user), RSBAC_UID_NUM(tid.user), argv[2], attr, value.dummy);
              else
                printf(gettext("Processing user %s (uid %u), attribute %s (No. %u), value %i\n"),
                       argv[i+3], RSBAC_UID_NUM(tid.user), argv[2], attr, value.dummy);
            }
          res = rsbac_set_attr(ta_number, module, target, &tid, attr, &value);
          show_error(res);
        }
    }
  else
    {
      use();
      return 1;
    }
  return (res);
}
