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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.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;

void use(void)
    {
      printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
      printf(gettext("Use: %s [flags] group\n"), progname);
      printf(gettext(" -h = this help, -- = no more flags,\n"));
      printf(gettext(" -v = verbose,\n"));
      printf(gettext(" -a user = add user to group,\n"));
      printf(gettext(" -d user = remove user from group,\n"));
      printf(gettext(" -M user,... = add user(s) to group,\n"));
      printf(gettext(" -A user,... = ignored, for compatibility\n"));
      printf(gettext(" -H hash-algo = hash algorithm to use, e.g. sha256 (default: use kernel default),\n"));
      printf(gettext(" -r = remove group password,\n"));
      printf(gettext(" -R = ignored, for compatibility\n"));
      printf(gettext(" -N ta = transaction number (group memberships only)\n"));
      printf(gettext("         (default = value of RSBAC_TA, if set, or 0)\n"));
    }

int main(int argc, char ** argv)
{
  int res = 0;
  rsbac_gid_t group = RSBAC_NO_GROUP;
  int removepass = 0;
  char * useraddstring = NULL;
  char * userdelstring = NULL;
  int verbose = 0;
  char * new_pass;
  char * new_pass2;
  char * hash_algo = NULL;
  rsbac_list_ta_number_t ta_number = 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 'R':
                exit(0);

              case 'r':
                removepass = 1;
                break;

              case 'a':
              case 'M':
                if(argc > 2)
                  {
                    useraddstring = argv[2];
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing argument for parameter %c\n"), progname, *pos);
                break;
              case 'd':
                if(argc > 2)
                  {
                    userdelstring = argv[2];
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing argument for parameter %c\n"), progname, *pos);
                break;
              case 'A':
                if(argc > 2)
                  {
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing argument for parameter %c\n"), progname, *pos);
                break;
              case 'H':
                if(argc > 2)
                  {
                    hash_algo = argv[2];
                    argc--;
                    argv++;
                  }
                else
                  fprintf(stderr, gettext("%s: missing value for parameter %c\n"), progname, *pos);
                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)
    {
      if(rsbac_um_get_gid(ta_number, argv[1], &group))
        {
          group = strtoul(argv[1],0,0);
          if(!group && strcmp(argv[1],"0"))
            {
              fprintf(stderr, gettext("%s: Unknown group %s\n"), progname, argv[1]);
              exit(1);
            }
        }
      if(removepass)
        {
          res = rsbac_um_set_group_pass(group, NULL);
          error_exit(res);
          exit(0);
        }
      if(useraddstring)
        {
          char * p;
          char * m;
          rsbac_uid_t user;

          m = useraddstring;
          p = useraddstring;
          while(*m)
            {
              while(*p && (*p != ','))
                p++;
              if(*p)
                {
                  *p = 0;
                  if(rsbac_um_get_uid(ta_number, m, &user))
                    {
                      char * q;

                      for (q = m; *q; q++)
                        {
                          if ((*q < '0') || (*q > '9'))
                            {
                              fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, m);
                              p++;
                              m = p;
                              break;
                            }
                        }
                      if (*q)
                        continue;
                      user = strtoul(m,0,0);
                    }
//                  printf("String %s, value %u\n", m, user);
                  p++;
                  m = p;
                }
              else
                {
                  if(rsbac_um_get_uid(ta_number, m, &user))
                    {
                      char * q;

                      for (q = m; *q; q++)
                        {
                          if ((*q < '0') || (*q > '9'))
                            {
                              fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, m);
                              p++;
                              m = p;
                              break;
                            }
                        }
                      if (*q)
                        continue;
                      user = strtoul(m,0,0);
                    }
//                  printf("String %s, value %u\n", m, user);
                  m = p;
                }
              if(verbose) {
                if (RSBAC_GID_SET(group))
                  printf("Adding group %u/%u member %u\n",
                         RSBAC_GID_SET(group),
                         RSBAC_GID_NUM(group),
                         RSBAC_UID_NUM(user));
                else
                  printf("Adding group %u member %u\n",
                         RSBAC_GID_NUM(group),
                         RSBAC_UID_NUM(user));
              }
              res = rsbac_um_add_gm(ta_number,
                                    RSBAC_GEN_UID(RSBAC_GID_SET(group), user),
                                    RSBAC_GID_NUM(group),
                                    0);
              if(res)
                {
                  if (RSBAC_GID_SET(group))
                    fprintf(stderr, "group %u/%u membership %u: ",
                            RSBAC_GID_SET(group),
                            RSBAC_GID_NUM(group),
                            RSBAC_UID_NUM(user));
                  else
                    fprintf(stderr, "group %u membership %u: ",
                            RSBAC_GID_NUM(group),
                            RSBAC_UID_NUM(user));
                  show_error(res);
                }
            }
          exit(0);
        }
      if(userdelstring)
        {
          char * p;
          char * m;
          rsbac_uid_t user;

          m = userdelstring;
          p = userdelstring;
          while(*m)
            {
              while(*p && (*p != ','))
                p++;
              if(*p)
                {
                  *p = 0;
                  if(rsbac_um_get_uid(ta_number, m, &user))
                    {
                      user = strtoul(m,0,0);
                      if(!user && strcmp(m,"0"))
                        {
                          fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, m);
                          p++;
                          m = p;
                          continue;
                        }
                    }
//                  printf("String %s, value %u\n", m, user);
                  p++;
                  m = p;
                }
              else
                {
                  if(rsbac_um_get_uid(ta_number, m, &user))
                    {
                      user = strtoul(m,0,0);
                      if(!user && strcmp(m,"0"))
                        {
                          fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, m);
                          m = p;
                          continue;
                        }
                    }
//                  printf("String %s, value %u\n", m, user);
                  m = p;
                }
              if(verbose) {
                if (RSBAC_GID_SET(group))
                  printf("Removing group %u/%u member %u\n",
                         RSBAC_GID_SET(group),
                         RSBAC_GID_NUM(group),
                         RSBAC_UID_NUM(user));
                else
                  printf("Removing group %u member %u\n",
                         RSBAC_GID_NUM(group),
                         RSBAC_UID_NUM(user));
              }
              res = rsbac_um_remove_gm(ta_number,
                                    RSBAC_GEN_UID(RSBAC_GID_SET(group), user),
                                    RSBAC_GID_NUM(group));
              if(res)
                {
                  if (RSBAC_GID_SET(group))
                    fprintf(stderr, "group %u/%u membership %u: ",
                            RSBAC_GID_SET(group),
                            RSBAC_GID_NUM(group),
                            RSBAC_UID_NUM(user));
                  else
                    fprintf(stderr, "group %u membership %u: ",
                            RSBAC_GID_NUM(group),
                            RSBAC_UID_NUM(user));
                  show_error(res);
                }
            }
          exit(0);
        }
      new_pass = malloc(RSBAC_MAXNAMELEN);
      printf("New password: ");
      if(scanf("%254s", new_pass) <= 0)
        {
          fprintf(stderr, gettext("%s: invalid new password!\n"), progname);
          exit(1);
        }
      new_pass2 = malloc(RSBAC_MAXNAMELEN);
      printf("Repeat new password: ");
      if(scanf("%254s", new_pass2) <= 0)
        {
          fprintf(stderr, gettext("%s: invalid repeated new password!\n"), progname);
          exit(1);
        }
      if(strcmp(new_pass, new_pass2))
        {
          fprintf(stderr, gettext("%s: new passwords do not match!\n"), progname);
          exit(1);
        }
      if (hash_algo)
        res = rsbac_um_set_group_pass_hash(group, new_pass, hash_algo);
      else
        res = rsbac_um_set_group_pass(group, new_pass);
      error_exit(res);
      exit(0);
    }
  else
    {
      use();
      exit(1);
    }
}
