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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.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

char * progname;

void use(void)
  {
    printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
    printf(gettext("Use: %s [switches] module group attribute [position|request-name]\n\n"), progname);  
    printf(gettext(" -h = this help, -- = no more flags,\n"));
    printf(gettext(" -n = numeric value, -b = both names and numbers,\n"));
    printf(gettext(" -l list all users, -L list all Linux groups\n"));
    printf(gettext(" -a = list attributes and values\n"));
    printf(gettext(" -N ta = transaction number (default = value of RSBAC_TA, if set, or 0)\n"));
    printf(gettext(" module = GEN, MAC, FC, SIM, UDF, MS, FF, RC or AUTH\n"));
  }

int main(int argc, char ** argv)
{
  int attr_list[RSBAC_GROUP_NR_ATTRIBUTES] = RSBAC_GROUP_ATTR_LIST;
  int res = 0;
  char tmp1[RSBAC_MAXNAMELEN],tmp2[RSBAC_MAXNAMELEN],tmp3[RSBAC_MAXNAMELEN];
  int j;
  enum rsbac_switch_target_t module = SW_NONE;
  union rsbac_attribute_value_t value;
  union rsbac_target_id_t tid;
  enum rsbac_attribute_t attr;
  int inherit = 0;
  int numeric = 0;
  int both = 0;
  int bothr = 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 'e':
                inherit=1;
                break;
              case 'p':
                break;
              case 'n':
                numeric=1;
                break;
              case 'b':
                both=1;
                break;
              case 'B':
                bothr=1;
                break;
              case 's':
                break;
              case 'l':
                {
                  struct passwd * user_info_p; 

                  setpwent();
                  while((user_info_p = getpwent()))
                    {
                      if(numeric)
                        printf("%u\n", user_info_p->pw_uid);
                      else
                      if(both)
                        printf("%s %u\n", user_info_p->pw_name, user_info_p->pw_uid);
                      else
                      if(bothr)
                        printf("%u %s\n", user_info_p->pw_uid, user_info_p->pw_name);
                      else
                        printf("%s\n", user_info_p->pw_name);
                    }
                  exit(0);
                }
              case 'L':
                {
                  struct group * group_info_p; 

                  setgrent();
                  while((group_info_p = getgrent()))
                    {
                      if(numeric)
                        printf("%u\n", group_info_p->gr_gid);
                      else
                      if(both)
                        printf("%s %u\n", group_info_p->gr_name, group_info_p->gr_gid);
                      else
                      if(bothr)
                        printf("%u %s\n", group_info_p->gr_gid, group_info_p->gr_name);
                      else
                        printf("%s\n", group_info_p->gr_name);
                    }
                  exit(0);
                }
              case 'g':
                if(argc > 2)
                  {
                    rsbac_gid_t gid;

                    if(rsbac_get_gid(ta_number, &gid, argv[2]))
                      {
                        fprintf(stderr, gettext("%s: Invalid Group %s!\n"),
                                progname, argv[2]);
                        exit(1);
                      }
                    if (RSBAC_GID_SET(gid))
                      printf("%u/%u\n", RSBAC_GID_SET(gid), RSBAC_GID_NUM(gid));
                    else
                      printf("%u\n", RSBAC_GID_NUM(gid));
                    exit(0);
                  }
                else
                  {
                    fprintf(stderr, "Missing argument to parameter g!\n");
                    exit(1);
                  }
              case 'a':
              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 returned value = see following list:\n"));
                for (j=0;j<RSBAC_GROUP_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);
                  }
                exit(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--;
        }
    }
  switch(argc)
    {
      case 3:
        value.dummy = -1;
        if(rsbac_get_gid_name(ta_number, &tid.group, tmp1, argv[1]))
          {
            fprintf(stderr, gettext("%s: Invalid Group %s!\n"),
                    progname, argv[1]);
            exit(1);
          }
        if(!strcmp("group_nr",argv[2]))
          {
            if (RSBAC_GID_SET(tid.group))
              printf("%u/%u\n", RSBAC_GID_SET(tid.group), RSBAC_GID_NUM(tid.group));
            else
              printf("%u\n", RSBAC_GID_NUM(tid.group));
            exit(0);
          }
        if(!strcmp("group_name",argv[2]))
          {
            printf("%s\n", tmp1);
            exit(0);
          }

        attr = get_attribute_nr(argv[2]);
        if(attr == A_none)
          {
            fprintf(stderr, gettext("%s: Invalid Attribute %s!\n"), progname, argv[2]);
            exit(1);
          }

        res = rsbac_get_attr(ta_number, module, T_GROUP, &tid, attr, &value, inherit);
        error_exit(res);
        switch(attr)
          {
            case A_rc_type:
              printf("%u\n",value.rc_role);
              break;
            default:
              printf("%i\n",value.dummy);
          }
        exit(0);

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