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

#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;
int verbose = 0;
int delhome = 0;
int nonumeric = 0;
rsbac_list_ta_number_t ta_number = 0;
rsbac_um_set_t vset = RSBAC_UM_VIRTUAL_KEEP;

void use(void)
    {
      printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
      printf(gettext("Use: %s [flags] user [user2 ...]\n"), progname);
      printf(gettext(" -h = this help, -- = no more flags,\n"));
      printf(gettext(" -v = verbose,\n"));
      printf(gettext(" -z = do not also try numeric username as uid\n"));
      printf(gettext(" -r = remove user's home dir\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"));
    }

int process(char * name)
  {
      int res = 0;
      int dh_tmp = delhome;
      rsbac_uid_t user = RSBAC_GEN_UID(vset, RSBAC_NO_USER);
      union rsbac_um_mod_data_t data;

      if(rsbac_um_get_uid(ta_number, name, &user))
        {
          char * p = name;
          rsbac_um_set_t tmp_vset = vset;

          if (nonumeric) {
            fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, name);
            return 1;
          }
          while (*p && (*p != '/'))
            p++;
          if (*p) {
                    *p = 0;
                    if (rsbac_get_vset_num(name, &tmp_vset))
                      {
                        fprintf(stderr, gettext("%s: invalid virtual set number %s, skipping\n"), progname, name);
                        return 1;
                      }
                    *p = '/';
                    p++;
                    name = p;
          }
          for (p = name; *p; p++)
            {
              if ((*p < '0') || (*p > '9'))
                {
                  fprintf(stderr, gettext("%s: Unknown user %s\n"), progname, name);
                  return 1;
                }
            }
          user = strtoul(name, NULL, 0);
          user = RSBAC_GEN_UID(tmp_vset, user);
        }
      if(verbose) {
        if (vset != RSBAC_UM_VIRTUAL_KEEP)
          printf("Deleting user %s, uid %u/%u\n",
                 name, RSBAC_UID_SET(user), RSBAC_UID_NUM(user));
        else
          printf("Deleting user %s, uid %u\n", name, RSBAC_UID_NUM(user));
      }
      if(dh_tmp)
        {
          res = rsbac_um_get_user_item(ta_number, user, UM_homedir, &data);
          if(res < 0)
            {
              if (vset != RSBAC_UM_VIRTUAL_KEEP)
                fprintf(stderr, "Getting user %u/%s homedir failed with error",
                        RSBAC_UID_SET(user), name);
              else
                fprintf(stderr, "Getting user %s homedir failed with error", name);
              show_error(res);
              fprintf(stderr, ", homedir will not be deleted!\n");
              dh_tmp = 0;
            }
        }
      res = rsbac_um_remove_user(ta_number, user);
      if(res)
        {
          if (vset != RSBAC_UM_VIRTUAL_KEEP)
            fprintf(stderr, "%u/%s: ", RSBAC_UID_SET(user), name);
          else
            fprintf(stderr, "%s: ", name);
          show_error(res);
          return res;
        }
      if(dh_tmp)
        {
          char command[RSBAC_MAXNAMELEN + 20];
          FILE * pfile;

          snprintf(command, RSBAC_MAXNAMELEN + 19, "/bin/rm -rf \"%s\"",
                   data.string);
          pfile = popen(command, "w");
          if(!pfile)
            {
              if (vset != RSBAC_UM_VIRTUAL_KEEP)
                fprintf(stderr, "Removing user %u/%s homedir %s failed with error",
                        RSBAC_UID_SET(user), name, data.string);
              else
                fprintf(stderr, "Removing user %s homedir %s failed with error", name, data.string);
              show_error(res);
              fprintf(stderr, "\n");
            }
          else
            {
              pclose(pfile);
            }
        }
      return 0;
  }


int main(int argc, char ** argv)
{
  locale_init();

  progname = argv[0];
  u_int stopflags = FALSE;

  {
    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':
                delhome=1;
                break;
              case 'z':
                nonumeric=1;
                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;
              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)
    {
      int i;

      for(i=1; i< argc; i++)
        process(argv[i]);
      exit(0);
    }
  else
    {
      use();
      return 1;
    }
  return (0);
}
