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

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/mman.h>
#include <iconv.h>

#include <rsbac/types.h>
#include <rsbac/syscalls.h>
#include <rsbac/error.h>
#include "nls.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

char * progname;
int verbose = 0;
int backup = 0;
int showpass = 0;
int printdates = 0;
int sanitize = 0;
char * separator = " ";
char adduidreplace[4] = "";
rsbac_list_ta_number_t ta_number = 0;
const char   add_prog[] = "rsbac_useradd";
const char   mod_prog[] = "rsbac_usermod";

rsbac_um_set_t vset = RSBAC_UM_VIRTUAL_KEEP;
iconv_t iconv_string_utf8_desc = (iconv_t) -1;

#define ROOM 20

#define NUMEXTRAUIDS 20

void use(void)
    {
      printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
      printf(gettext("Use: %s [flags] username\n"), progname);
      printf(gettext(" -h = this help, -- = no more flags,\n"));
      printf(gettext(" -v = verbose,\n"));
      printf(gettext(" -n = min uid to list (specify before list flag)\n"));
      printf(gettext(" -x = max uid to list (specify before list flag)\n"));
      printf(gettext(" -X n = also show uid n (before list flag, set max. %u uids)\n"), NUMEXTRAUIDS);
      printf(gettext(" -Y n = do not show uid n (before list flag, set max. %u uids)\n"), NUMEXTRAUIDS);
      printf(gettext(" -i string = only list users with string in name or full name (before list flag)\n"));
      printf(gettext(" -d = count all users to be listed\n"));
      printf(gettext(" -a = list all users\n"));
      printf(gettext(" -l = short list all users,\n"));
      printf(gettext(" -f = short list all users with full names,\n"));
      printf(gettext(" -F = short list all user names with full names, no id,\n"));
      printf(gettext(" -L = short list all users with shell,\n"));
      printf(gettext(" -M = short list all users with shell, no id,\n"));
      printf(gettext(" -B = short list all users with shell and full names,\n"));
      printf(gettext(" -P = short list all users with pseudo and full names,\n"));
      printf(gettext(" -c = CSV list of all users with items:\n"));
      printf("      vset:uid:name:fullname:shell:dir:group:moregroups\n");
      printf(gettext(" -C = CSV list of all users with items:\n"));
      printf("      vset:uid:name:fullname:shell:dir:group:moregroups:lastchange:minchange\n       :maxchange:warnchange:inactive:expire:ttl:maxhist\n");
      printf(gettext(" -o = append :pseudo to CSV list of all users (set before -c/-C)\n"));
      printf(gettext(" -s sep = separator string between items in short list (default space)\n"));
      printf(gettext(" -b = backup mode\n"));
      printf(gettext(" -r = add -r flag to rsbac_useradd (requires -b)\n"));
      printf(gettext(" -p = also show encrypted password\n"));
      printf(gettext(" -z = do not also try numeric username as uid\n"));
      printf(gettext(" -Z = truncate all names at first invalid UTF-8 character,\n"));
      printf(gettext("      skip invalid usernames in lists\n"));
      printf(gettext(" -D = print dates as yyyymmdd, not day number\n"));
      printf(gettext(" -u = list calling user\n"));
      printf(gettext(" -S n = virtual user set n\n"));
      printf(gettext(" -N ta = transaction number (default = value of RSBAC_TA, if set, or 0)\n"));
    }

void pass_print(__u8 * pass, u_int len)
  {
    u_int i;

    for(i=0; i<len; i++)
      {
        printf("%02x", pass[i]);
      }
  }

/* returns 1, if string has been changed, and 0, if not */
int do_sanitize(char * string, unsigned int buflen)
{
  int len = strlen(string);
  char * iconv_inbuf;
  char * iconv_outbuf;
  size_t iconv_inleft;
  size_t iconv_inlen;
  size_t iconv_outleft;
  size_t iconv_result = (size_t) -1;
  char * iconv_outbuf_start;
  unsigned int newlen;

  if (!string || !buflen)
    return 0;

  if (iconv_string_utf8_desc == (iconv_t) -1) {
    iconv_string_utf8_desc = iconv_open ("UTF-8//TRANSLIT", "UTF-8");
    if (iconv_string_utf8_desc == (iconv_t) -1) {
      fprintf(stderr, gettext("%s: do_sanitize(): iconv_open() failed with error: %s\n"), progname, strerror(errno));
      exit(1);
    }
  }

  iconv_inlen = len;
  iconv_inbuf = string;
  iconv_outleft = iconv_inlen * 2;
  iconv_outbuf = (char *) malloc(iconv_outleft + 1);
  if (!iconv_outbuf) {
    fprintf(stderr, gettext("%s: do_sanitize(): failed to malloc\n"), progname);
    exit(1);
  }
  iconv_outbuf_start = iconv_outbuf;

  while(iconv_result == (size_t) -1 && iconv_inlen > 0) {
    iconv_inleft = iconv_inlen;
    iconv_result = iconv(iconv_string_utf8_desc, &iconv_inbuf, &iconv_inleft, &iconv_outbuf, &iconv_outleft);
    if (iconv_result == (size_t) -1) {
      iconv_inlen--;
      string[iconv_inlen] = 0;
    }
  }
  if (iconv_inlen > 0) {
    *iconv_outbuf = 0;
    newlen = iconv_outbuf - iconv_outbuf_start;
    if (newlen >= buflen)
      newlen = buflen - 1;
    strncpy(string, iconv_outbuf_start, newlen);
    string[newlen] = 0;
  } else {
    string[0] = 0;
    newlen = 0;
  }

  free(iconv_outbuf_start);
  if (newlen == len)
    return 0;
  else
    return 1;
}

int process(rsbac_uid_t user)
  {
      union rsbac_um_mod_data_t data;
      int res;
      char username[RSBAC_MAXNAMELEN];

      res = rsbac_um_get_user_item(ta_number, user, UM_name, &data);
      if(!res)
        {
          if (sanitize && do_sanitize(data.string, RSBAC_MAXNAMELEN) && backup)
          {
            if (RSBAC_UID_SET(user) != RSBAC_UM_VIRTUAL_KEEP)
              fprintf(stderr, gettext("%s: user %u/%u has invalid username, skipping\n"),
                      progname, RSBAC_UID_SET(user), RSBAC_UID_NUM(user));
            else
              fprintf(stderr, gettext("%s: user %u has invalid username, skipping\n"),
                      progname, RSBAC_UID_NUM(user));
            return -1;
          }
          strcpy(username, data.string);
          if(backup)
            {
              if (RSBAC_UID_SET(user) != RSBAC_UM_VIRTUAL_KEEP)
                printf("%s%s -S %u -u %u %s\n",
                       add_prog, adduidreplace,
                       RSBAC_UID_SET(user), RSBAC_UID_NUM(user), username);
              else
                printf("%s%s -u %u %s\n", add_prog, adduidreplace,
                       RSBAC_UID_NUM(user), username);
            }
          else
            {
              printf("\n");
              if (RSBAC_UID_SET(user) != RSBAC_UM_VIRTUAL_KEEP)
                printf("Virtual Set: %u\n", RSBAC_UID_SET(user));
              printf("Uid: %u\n", RSBAC_UID_NUM(user));
              printf("Name: %s\n", data.string);
            }
        }
      else
        {
          if (RSBAC_UID_SET(user) != RSBAC_UM_VIRTUAL_KEEP)
            fprintf(stderr, gettext("%s: Unknown user %u/%u\n"),
                    progname, RSBAC_UID_SET(user), RSBAC_UID_NUM(user));
          else
            fprintf(stderr, gettext("%s: Unknown user %u\n"),
                    progname, RSBAC_UID_NUM(user));
          exit(1);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_fullname, &data);
      if(!res)
        {
          if (sanitize)
            do_sanitize(data.string, RSBAC_MAXNAMELEN);
          if(backup) {
            if (RSBAC_UID_SET(user) != RSBAC_UM_VIRTUAL_KEEP)
              printf("%s -S %u -c \"%s\"", mod_prog, RSBAC_UID_SET(user), data.string);
            else
              printf("%s -c \"%s\"", mod_prog, data.string);
          }
          else
            printf("Fullname: %s\n", data.string);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_shell, &data);
      if(!res)
        {
          if(backup)
            printf(" -s \"%s\"", data.string);
          else
            printf("Shell: %s\n", data.string);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_homedir, &data);
      if(!res)
        {
          if(backup)
            printf(" -d \"%s\"", data.string);
          else
            printf("Homedir: %s\n", data.string);
        }
      if(showpass)
        {
          rsbac_boolean_t oldpass = FALSE;

          res = mlock(&data, RSBAC_MAXNAMELEN);
	  if (res) {
		  fprintf(stderr, gettext("Unable to lock password into physical memory, continue anyway!\n"));
	  }
	  res = rsbac_um_get_user_item(ta_number, user, UM_pass_algo, &data);
	  if (res || data.string[0] == RSBAC_UM_PW_HASH_OLD_DEFAULT_NUM) {
	    if (res && verbose) {
	      fprintf(stderr, gettext("rsbac_um_get_user_item for UM_pass_algo: fallback to UM_pass: "));
	      show_error(res);
            }
	    oldpass = TRUE;
	    res = rsbac_um_get_user_item(ta_number, user, UM_pass, &data);
          }
          if(!res)
            {
              if(backup)
                {
                  printf(" -Q ");
                  pass_print((__u8 *) data.string, oldpass ? RSBAC_UM_PASS_LEN : RSBAC_UM_PWDATA_LEN);
                }
              else
                {
                  printf("Password: ");
                  pass_print((__u8 *) data.string, oldpass ? RSBAC_UM_PASS_LEN : RSBAC_UM_PWDATA_LEN);
                  printf("\n");
                }
            }
	  memset(&data, 0, RSBAC_MAXNAMELEN);
	  munlock(&data, RSBAC_MAXNAMELEN);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_group, &data);
      if(!res)
        {
          if(backup)
            printf(" -g %u", data.group);
          else
            printf("Group: %u\n", data.group);
        }
      {
        rsbac_gid_num_t * group_array = NULL;
        int group_num = 0;
        int i;

        group_num = rsbac_um_get_gm_list(ta_number, user, NULL, 0);
        if(group_num > 0)
          {
            group_num += ROOM;
            group_array = malloc(group_num * sizeof(*group_array));
	    if(!group_array)
              {
                error_exit(-RSBAC_ENOMEM);
              }
            group_num = rsbac_um_get_gm_list(ta_number, user, group_array, group_num);
            if(group_num > 0)
              {
                qsort(group_array, group_num, sizeof(*group_array), rsbac_group_compare);
                if(backup)
                  {
                    printf(" -I");
                    for(i=0; i<group_num; i++)
                      if(!i)
                        printf(" %u", group_array[i]);
                      else
                        printf(",%u", group_array[i]);
                  }
                else
                  {
                    printf("More groups:");
                    for(i=0; i<group_num; i++)
                      if(!i)
                        printf(" %u", group_array[i]);
                      else
                        printf(",%u", group_array[i]);
                    printf("\n");
                  }
              }
            else
              {
                if(backup)
                    printf(" -I \"\"");
              }
            free(group_array);
          }
        else
          {
            if(backup)
                printf(" -I \"\"");
          }
      }

      res = rsbac_um_get_user_item(ta_number, user, UM_lastchange, &data);
      if(!res)
        {
          if(backup)
            printf(" -l %u", data.days);
          else
          if(printdates)
            {
              struct tm * tm_p;
              time_t secs;

              secs = data.days * 86400;
              
              tm_p = gmtime(&secs);
              if(tm_p)
                printf("Lastchange: %04u%02u%02u\n",
                       tm_p->tm_year + 1900,
                       tm_p->tm_mon + 1,
                       tm_p->tm_mday);
            }
          else
            printf("Lastchange: %u\n", data.days);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_minchange, &data);
      if(!res)
        {
          if(backup)
            printf(" -n %u", data.days);
          else
            printf("Minchange: %u\n", data.days);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_maxchange, &data);
      if(!res)
        {
          if(backup)
            printf(" -x %u", data.days);
          else
            printf("Maxchange: %u\n", data.days);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_warnchange, &data);
      if(!res)
        {
          if(backup)
            printf(" -w %u", data.days);
          else
            printf("Warnchange: %u\n", data.days);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_inactive, &data);
      if(!res)
        {
          if(backup)
            printf(" -f %i", data.days);
          else
            printf("Inactive: %u\n", data.days);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_expire, &data);
      if(!res)
        {
          if(backup)
            printf(" -e %i", data.days);
          else
          if(printdates)
            {
              struct tm * tm_p;
              time_t secs;

              secs = data.days * 86400;
              
              tm_p = gmtime(&secs);
              if(tm_p)
                printf("Expire: %04u%02u%02u\n",
                       tm_p->tm_year + 1900,
                       tm_p->tm_mon + 1,
                       tm_p->tm_mday);
            }
          else
            printf("Expire: %u\n", data.days);
        }
      res = rsbac_um_get_user_item(ta_number, user, UM_ttl, &data);
      if(!res)
        {
          if(backup)
            {
              if(data.ttl)
                printf(" -T %lu", data.ttl + time(NULL));
            }
          else
            printf("Account TTL: %u\n", data.ttl);
        }

      res = rsbac_um_get_max_history(ta_number, user);
      if(res >= 0)
        {
          if(backup)
            {
              printf(" -i %u", res);
            }
          else
            printf("Max history: %u\n", res);
        }

      if(backup)
        {
          printf(" %s\n", username);
        }
      return 0;
  }

int main(int argc, char ** argv)
{
  int res = 0;
  int i;
  int list = 0;
  int listfull = 0;
  int listfullnoid = 0;
  int listshell = 0;
  int listshellnoid = 0;
  int listshellfull = 0;
  int listpseudofull = 0;
  int listcsv = 0;
  int listcsvfull = 0;
  int listwithpseudo = 0;
  int countlist = 0;
  int nonumeric = 0;
  char * filter = NULL;
  rsbac_uid_num_t minuid = 0;
  rsbac_uid_num_t maxuid = (rsbac_uid_num_t) -1;
  rsbac_uid_num_t extrauids[NUMEXTRAUIDS];
  int extrauidnum = 0;
  rsbac_uid_num_t skipuids[NUMEXTRAUIDS];
  int skipuidnum = 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 'b':
                backup = 1;
                break;
              case 'r':
                sprintf(adduidreplace, " -r");
                break;

              case 'p':
                showpass = 1;
                break;
              case 'z':
                nonumeric = 1;
                break;

              case 'D':
                printdates = 1;
                break;

              case 'u':
                process(RSBAC_GEN_UID(RSBAC_UM_VIRTUAL_KEEP,getuid()));
                exit(0);

              case 's':
                if(argc > 2)
                  {
                    separator = argv[2];
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing string value for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;
              case 'Z':
                sanitize = 1;
                break;
              case 'n':
                if(argc > 2)
                  {
                    minuid = strtoul(argv[2], 0, 10);
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing number value for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;
              case 'x':
                if(argc > 2)
                  {
                    maxuid = strtoul(argv[2], 0, 10);
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing number value for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;
              case 'X':
                if(argc > 2)
                  {
                    if (extrauidnum < NUMEXTRAUIDS)
                      extrauids[extrauidnum++] = strtoul(argv[2], 0, 10);
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing number value for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;
              case 'Y':
                if(argc > 2)
                  {
                    if (skipuidnum < NUMEXTRAUIDS)
                      skipuids[skipuidnum++] = strtoul(argv[2], 0, 10);
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing number value for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;
              case 'i':
                if(argc > 2)
                  {
                    filter = argv[2];
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing string for parameter %c\n"), progname, *pos);
                    exit(1);
                  }
                break;
              case 'o':
                listwithpseudo = 1;
                break;
              case 'd':
                countlist = 1;
                /* fall through */
              case 'C':
                listcsvfull = 1;
                /* fall through */
              case 'c':
                listcsv = 1;
                /* fall through */
              case 'P':
                listpseudofull = 1;
                /* fall through */
              case 'B':
                listshellfull = 1;
                /* fall through */
              case 'M':
                listshellnoid = 1;
                /* fall through */
              case 'L':
                listshell = 1;
                /* fall through */
              case 'F':
                listfullnoid = 1;
                /* fall through */
              case 'f':
                listfull = 1;
                /* fall through */
              case 'l':
                list = 1;
                /* fall through */
              case 'a':
                {
                  rsbac_uid_t * user_array = NULL;
                  int user_num = 0;
                  int i;
                  int j;
                  union rsbac_attribute_value_t value;
                  union rsbac_target_id_t tid;
                  rsbac_gid_num_t * group_array = NULL;
                  int group_num = 0;

                  user_num = rsbac_um_get_user_list(ta_number, vset, NULL, 0);
                  error_exit(user_num);
                  user_num += ROOM;
                  user_array = malloc(user_num * sizeof(*user_array));
	          if(!user_array)
	            {
                      error_exit(-RSBAC_ENOMEM);
	            }
                  user_num = rsbac_um_get_user_list(ta_number, vset, user_array, user_num);
                  error_exit(user_num);
                  if(user_num > 0)
                    {
                      qsort(user_array, user_num, sizeof(*user_array), rsbac_user_compare);
                      if(list)
                        {
                          union rsbac_um_mod_data_t data;
                          union rsbac_um_mod_data_t fullnamedata;
                          unsigned user_count = 0;

                          for(i=0; i<user_num; i++)
                            {
                              if (RSBAC_UID_NUM(user_array[i]) < minuid || RSBAC_UID_NUM(user_array[i]) > maxuid) {
                                res = -1;
                                if (extrauidnum > 0) {
                                  for(j=0; j<extrauidnum; j++) {
                                    if (RSBAC_UID_NUM(user_array[i]) == extrauids[j]) {
                                      res = j;
                                      break;
                                    }
                                  }
                                }
                                if (res == -1)
                                  continue;
                              }
                              res = -1;
                              if (skipuidnum > 0) {
                                for(j=0; j<skipuidnum; j++) {
                                  if (RSBAC_UID_NUM(user_array[i]) == skipuids[j]) {
                                    res = j;
                                    break;
                                  }
                                }
                              }
                              if (res != -1)
                                continue;
                              res = rsbac_um_get_user_item(ta_number, user_array[i], UM_name, &data);
                              if(!res) {
                                if (sanitize && do_sanitize(data.string, RSBAC_MAXNAMELEN))
                                  {
                                    if (RSBAC_UID_SET(user_array[i]) != RSBAC_UM_VIRTUAL_KEEP)
                                      fprintf(stderr, gettext("%s: user %u/%u has invalid username, skipping\n"),
                                              progname, RSBAC_UID_SET(user_array[i]), RSBAC_UID_NUM(user_array[i]));
                                    else
                                      fprintf(stderr, gettext("%s: user %u has invalid username, skipping\n"),
                                              progname, RSBAC_UID_NUM(user_array[i]));
                                    continue;
                                  }
                                res = rsbac_um_get_user_item(ta_number, user_array[i], UM_fullname, &fullnamedata);
                                if(res)
                                  fullnamedata.string[0] = 0;
                                else if (sanitize) {
                                  do_sanitize(fullnamedata.string, RSBAC_MAXNAMELEN);
                                }
                                if (filter && !strstr(data.string, filter) && !strstr(fullnamedata.string, filter))
                                    continue;
                                if (countlist)
                                  {
                                    user_count++;
                                    continue;
                                  }
                                if (listcsv) {
                                  /* vset:uid:name:fullname:shell:dir:group:moregroups */
                                  /* vset:uid:name:fullname:shell:dir:group:moregroups:lastchange:minchange:maxchange:warnchange:inactive:expire:ttl:maxhist */
                                  tid.user = user_array[i];
                                  printf("%u:%u:%s:%s", RSBAC_UID_SET(tid.user), RSBAC_UID_NUM(tid.user), data.string, fullnamedata.string);
                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_shell, &data);
                                  if(!res)
                                    printf(":%s", data.string);
                                  else
                                    printf(":");
                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_homedir, &data);
                                  if(!res)
                                    printf(":%s", data.string);
                                  else
                                    printf(":");
                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_group, &data);
                                  if(!res)
                                    printf(":%u", data.group);
                                  else
                                    printf(":");
                                  group_num = rsbac_um_get_gm_list(ta_number, user_array[i], NULL, 0);
                                  if(group_num > 0) {
                                    group_num += ROOM;
                                    group_array = malloc(group_num * sizeof(*group_array));
                                    if(!group_array)
                                      error_exit(-RSBAC_ENOMEM);
                                    group_num = rsbac_um_get_gm_list(ta_number, user_array[i], group_array, group_num);
                                    if(group_num > 0) {
                                      qsort(group_array, group_num, sizeof(*group_array), rsbac_group_compare);
                                      for(j=0; j<group_num; j++)
                                      if(!j)
                                        printf(":%u", group_array[j]);
                                      else
                                        printf(",%u", group_array[j]);
                                    } else {
                                      printf(":");
                                    }
                                    free(group_array);
                                  } else {
                                    printf(":");
                                  }
                                  if (listcsvfull) {
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_lastchange, &data);
                                    if(!res)
                                      printf(":%u", data.days);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_minchange, &data);
                                    if(!res)
                                      printf(":%u", data.days);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_maxchange, &data);
                                    if(!res)
                                      printf(":%u", data.days);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_warnchange, &data);
                                    if(!res)
                                      printf(":%u", data.days);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_inactive, &data);
                                    if(!res)
                                      printf(":%u", data.days);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_expire, &data);
                                    if(!res)
                                      printf(":%u", data.days);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_ttl, &data);
                                    if(!res)
                                      printf(":%u", data.ttl);
                                    else
                                      printf(":");
                                    res = rsbac_um_get_max_history(ta_number, user_array[i]);
                                    if(res >= 0)
                                      printf(":%u", res);
                                    else
                                      printf(":");
                                  }
                                  if (listwithpseudo) {
                                    res = rsbac_get_attr(ta_number, SW_GEN, T_USER, &tid, A_pseudo, &value, 0);
                                    if(!res)
                                      printf(":%u", value.pseudo);
                                    else
                                      printf(":");
                                  }
                                  printf("\n");
                                } else if (listpseudofull) {
                                  tid.user = user_array[i];
                                  res = rsbac_get_attr(ta_number, SW_GEN, T_USER, &tid, A_pseudo, &value, 0);
                                  if(!res) {
                                    union rsbac_um_mod_data_t data3;

                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_fullname, &data3);
                                    if(!res) {
                                      if (sanitize)
                                        do_sanitize(data3.string, RSBAC_MAXNAMELEN);
                                      if (RSBAC_UID_SET(user_array[i]) > 0)
                                        printf("%u/%s%s%u%s%u%s%s\n",
                                             RSBAC_UID_SET(user_array[i]),
                                             data.string,
                                             separator,
                                             RSBAC_UID_NUM(user_array[i]),
                                             separator,
                                             value.pseudo,
                                             separator,
                                             data3.string);
                                      else
                                        printf("%s%s%u%s%u%s%s\n",
                                             data.string,
                                             separator,
                                             RSBAC_UID_NUM(user_array[i]),
                                             separator,
                                             value.pseudo,
                                             separator,
                                             data3.string);
                                    }
                                  }
                                } else if (listshellfull) {
                                  union rsbac_um_mod_data_t data2;

                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_shell, &data2);
                                  if(!res) {
                                    union rsbac_um_mod_data_t data3;

                                    res = rsbac_um_get_user_item(ta_number, user_array[i], UM_fullname, &data3);
                                    if(!res) {
                                      if (sanitize)
                                        do_sanitize(data3.string, RSBAC_MAXNAMELEN);
                                      if (RSBAC_UID_SET(user_array[i]) > 0)
                                        printf("%u/%s%s%u%s%s%s%s\n",
                                             RSBAC_UID_SET(user_array[i]),
                                             data.string,
                                             separator,
                                             RSBAC_UID_NUM(user_array[i]),
                                             separator,
                                             data2.string,
                                             separator,
                                             data3.string);
                                      else
                                        printf("%s%s%u%s%s%s%s\n",
                                             data.string,
                                             separator,
                                             RSBAC_UID_NUM(user_array[i]),
                                             separator,
                                             data2.string,
                                             separator,
                                             data3.string);
                                    }
                                  }
                                } else if (listshellnoid) {
                                  union rsbac_um_mod_data_t data2;

                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_shell, &data2);
                                  if(!res) {
                                    if (RSBAC_UID_SET(user_array[i]) > 0)
                                      printf("%u/%s%s%s\n",
                                           RSBAC_UID_SET(user_array[i]),
                                           data.string,
                                           separator,
                                           data2.string);
                                    else
                                      printf("%s%s%s\n",
                                           data.string,
                                           separator,
                                           data2.string);
                                  }
                                } else if (listshell) {
                                  union rsbac_um_mod_data_t data2;

                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_shell, &data2);
                                  if(!res) {
                                    if (RSBAC_UID_SET(user_array[i]) > 0)
                                      printf("%u/%s%s%u%s%s\n",
                                           RSBAC_UID_SET(user_array[i]),
                                           data.string,
                                           separator,
                                           RSBAC_UID_NUM(user_array[i]),
                                           separator,
                                           data2.string);
                                    else
                                      printf("%s%s%u%s%s\n",
                                           data.string,
                                           separator,
                                           RSBAC_UID_NUM(user_array[i]),
                                           separator,
                                           data2.string);
                                  }
                                } else if (listfullnoid) {
                                  union rsbac_um_mod_data_t data2;

                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_fullname, &data2);
                                  if(!res) {
                                    if (sanitize)
                                      do_sanitize(data2.string, RSBAC_MAXNAMELEN);
                                    if (RSBAC_UID_SET(user_array[i]) > 0)
                                      printf("%u/%s%s%s\n",
                                           RSBAC_UID_SET(user_array[i]),
                                           data.string,
                                           separator,
                                           data2.string);
                                    else
                                      printf("%s%s%s\n",
                                           data.string,
                                           separator,
                                           data2.string);
                                  }
                                } else if (listfull) {
                                  union rsbac_um_mod_data_t data2;

                                  res = rsbac_um_get_user_item(ta_number, user_array[i], UM_fullname, &data2);
                                  if(!res) {
                                    if (sanitize)
                                      do_sanitize(data2.string, RSBAC_MAXNAMELEN);
                                    if (RSBAC_UID_SET(user_array[i]) > 0)
                                      printf("%u/%s%s%u%s%s\n",
                                           RSBAC_UID_SET(user_array[i]),
                                           data.string,
                                           separator,
                                           RSBAC_UID_NUM(user_array[i]),
                                           separator,
                                           data2.string);
                                    else
                                      printf("%s%s%u%s%s\n",
                                           data.string,
                                           separator,
                                           RSBAC_UID_NUM(user_array[i]),
                                           separator,
                                           data2.string);
                                  }
                                } else {
                                  if (RSBAC_UID_SET(user_array[i]) > 0)
                                    printf("%u/%s%s%u\n",
                                         RSBAC_UID_SET(user_array[i]),
                                         data.string,
                                         separator,
                                         RSBAC_UID_NUM(user_array[i]));
                                  else
                                    printf("%s%s%u\n",
                                         data.string,
                                         separator,
                                         RSBAC_UID_NUM(user_array[i]));
                                }
                              }
                            }
                          if (countlist)
                            {
                              printf("%u\n", user_count);
                            }
                        }
                      else
                        for(i=0; i<user_num; i++)
                          process(user_array[i]);
                    }
                  free(user_array);
                  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;
              case 'S':
                if(argc > 2)
                  {
                    if (rsbac_get_vset_num(argv[2], &vset))
                      {
                        fprintf(stderr, gettext("%s: invalid virtual set number for parameter %c\n"), progname, *pos);
                        exit(1);
                      }
                    argc--;
                    argv++;
                  }
                else
                  {
                    fprintf(stderr, gettext("%s: missing virtual set number 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)
    {
      for(i=1; i<argc; i++)
        {
          rsbac_uid_t user = RSBAC_GEN_UID(vset, RSBAC_NO_USER);
          if(rsbac_um_get_uid(ta_number, argv[i], &user))
            {
              char * tmp_name = argv[i];
              char * p = tmp_name;
              rsbac_um_set_t tmp_vset = vset;

              if (nonumeric) {
                fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, argv[i]);
                return 1;
              }
              while (*p && (*p != '/'))
                p++;
              if (*p) {
                    *p = 0;
                    if (rsbac_get_vset_num(tmp_name, &tmp_vset))
                      {
                        fprintf(stderr, gettext("%s: invalid virtual set number %s, skipping\n"), progname, tmp_name);
                        continue;
                      }
                    *p = '/';
                    p++;
                    tmp_name = p;
              }
              for (p = tmp_name; *p; p++)
                {
                  if ((*p < '0') || (*p > '9'))
                    {
                      fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, argv[i]);
                      return 1;
                    }
                }
              user = strtoul(tmp_name, NULL, 0);
              user = RSBAC_GEN_UID(tmp_vset, user);
            }
          process(user);
        }
      if (iconv_string_utf8_desc != (iconv_t) -1)
        iconv_close(iconv_string_utf8_desc);
      exit(0);
    }
  else
    {
      use();
      return 1;
    }
  return (res);
}
