#!/usr/bin/perl -I/usr/local/sauron
#
# moduser - utility to modify user/group rights
#
# Copyright (c) Michal Kostenec <kostenec@civ.zcu.cz> 2013-2014.
# Copyright (c) Timo Kokkonen <tjko@iki.fi>  2000-2004.
# $Id: moduser,v 1.44 2008/03/31 08:43:31 tjko Exp $
#
require 5;
use Time::Local;
use Getopt::Long;
use Sauron::DB;
use Sauron::Util;
use Sauron::BackEnd;
use Sauron::Sauron;

my ($PG_DIR,$PG_NAME) = ($0 =~ /^(.*\/)(.*)$/);
$0 = $PG_NAME;

load_config();

$modgroup = ($PG_NAME eq 'modgroup' ? 1 : 0);
$fooname=($modgroup ? 'groupname' : 'username');
$SAURON_PWD_MODE = 0 unless (defined($SAURON_PWD_MODE));

$user = (getpwuid($<))[0];
$mdate = time;

%addmodes=('group'=>0,'server'=>1,'zone'=>2,'net'=>3,'hostmask'=>4,'ipmask'=>5,
	   'level'=>6,'elimit'=>7,'defdept'=>8,'tmplmask'=>9,
	   'grpmask'=>10,'delmask'=>11,'rhf'=>12,'flag'=>13);

%masktypes=(4=>'Hostmask',9=>'Template',10=>'Group',11=>'Delete');

############################################

sub ask_mode($) {
  my($n) = @_;
  my($mode,$t,$i);
  my(%modehash);

  if ($n==1) { %modehash=(1=>'RW',2=>'RWX'); }
  else { %modehash=(1=>'R',2=>'RW',3=>'RWX'); }
  print "Enter mode [";
  foreach $i (keys %modehash) { print "$i=$modehash{$i} "; }
  print "]: ";

  chomp($t = <STDIN>);
  $mode=$modehash{$t};

  return $mode;
}


sub list_privs($$) {
  my($id,$utype) = @_;
  my($i,@d);

  db_query("SELECT a.rule,b.name,a.id FROM user_rights a, servers b " .
	   "WHERE a.rtype=1 AND a.rref=b.id AND a.ref=$id AND a.type=$utype ".
	   "ORDER BY b.name",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][2],"server",$d[$i][1],$d[$i][0];
  }

  db_query("SELECT a.rule,c.name||':'||b.name,a.id " .
	   "FROM user_rights a, zones b, servers c " .
	   "WHERE a.rtype=2 AND a.rref=b.id AND b.server=c.id AND " .
	   " a.ref=$id AND a.type=$utype ORDER BY b.name",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][2],"zone",$d[$i][1],$d[$i][0];
  }

  db_query("SELECT a.rule,b.net,a.id,c.name " .
	   "FROM user_rights a, nets b, servers c " .
	   "WHERE a.rtype=3 AND a.rref=b.id AND b.server=c.id " .
           "  AND a.ref=$id AND a.type=$utype ORDER BY b.net",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][2],"net",$d[$i][3].':'.$d[$i][1],
      '(IP constraint)';
  }

  db_query("SELECT a.rule,a.id,null FROM user_rights a " .
	   "WHERE a.rtype=4 AND a.ref=$id AND a.type=$utype AND a.rref=-1" .
	   "UNION ALL " .
	   "SELECT a.rule,a.id,z.name FROM user_rights a " .
	   "JOIN zones z ON a.rref=z.id " .
	   "WHERE a.rtype=4 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"hostmask",
      ($d[$i][2] ? $d[$i][2] .":" : "") . $d[$i][0] ,
      "(hostname constraint)";
  }

  db_query("SELECT a.rule,a.id  FROM user_rights a " .
	   "WHERE a.rtype=5 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"IP-mask",$d[$i][0],
      "(IP constraint)";
  }

  db_query("SELECT a.rule,a.id  FROM user_rights a " .
	   "WHERE a.rtype=6 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"Level",$d[$i][0],
      "(privilege level)";
  }

  db_query("SELECT a.rule,a.id  FROM user_rights a " .
	   "WHERE a.rtype=7 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"ELimit",$d[$i][0],
      "(expiration limit)";
  }

  db_query("SELECT a.rule,a.id  FROM user_rights a " .
	   "WHERE a.rtype=8 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"DefDept",$d[$i][0],
      "(default department string)";
  }

  db_query("SELECT a.rule,a.id  FROM user_rights a " .
	   "WHERE a.rtype=9 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"TmplMask",$d[$i][0],
      "(Template mask)";
  }

  db_query("SELECT a.rule,a.id  FROM user_rights a " .
	   "WHERE a.rtype=10 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"GrpMask",$d[$i][0],
      "(Group mask)";
  }

  db_query("SELECT a.rule,a.id,null FROM user_rights a " .
          "WHERE a.rtype=11 AND a.ref=$id AND a.type=$utype AND a.rref=-1" .
          "UNION ALL " .
          "SELECT a.rule,a.id,z.name FROM user_rights a " .
          "JOIN zones z ON a.rref=z.id " .
          "WHERE a.rtype=11 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"Delmask",
      ($d[$i][2] ? $d[$i][2] .":" : "") . $d[$i][0] ,
      "(Host delete mask)";
  }

  db_query("SELECT a.rule,a.id,a.rref  FROM user_rights a " .
	   "WHERE a.rtype=12 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"RHF",$d[$i][0],
      ($d[$i][2] ? 'optional' : 'required');
  }

  db_query("SELECT a.rule,a.id,a.rref  FROM user_rights a " .
	   "WHERE a.rtype=13 AND a.ref=$id AND a.type=$utype ORDER BY id",\@d);
  for $i (0..$#d) {
    $d[$i][0] =~ s/\s+$//;
    printf "%-6s %-8s %-44s %s\n",$d[$i][1],"Flag",$d[$i][0],
           '(privilege flag)';
  }
}

##############################################

GetOptions("help|h","list!","add:s","delall!","del=s","passwd:s",
	   "name=s","superuser=s","lock!","unlock!","edit!",
	   "email=s","comment=s","expiration=s");

$opt_user=$ARGV[0];

if ($opt_help || ($opt_user eq '' &&  $opt_list eq '')) {
  print "syntax: $0 <$fooname> [options]\n\n";
  print " Option descriptions: \n";

  print "   --name=\"user name\"                    full user name\n",
       "   --email=<address>                     set user's email address\n",
       "   --comment=<text>                      set user comments\n",
       "   --expiration=<DD-MM-YYYY> | NONE      set account expiration\n",
       "   --superuser=<yes|no>                  toggle superuser flag\n",
       "   --passwd                              set password (interactive)\n",
       "   --passwd=<password>                   set password\n",
       "   --list                                list all $fooname\n",
       "   --lock                                lock account\n",
       "   --unlock                              unlock account\n\n"
         unless ($modgroup);

  # "groups in groups" not done yet ...
  print "   --list                                list all groups\n"
      if ($modgroup);

  print "                                         Priviliges\n",
        "   --add                                 interactive add\n";
  print	"   --add=\"group,<groupname>\"             add group membership\n" 
      unless ($modgroup);

  print "   --add=\"server,<servername>,<mode>\"    add server (mode=R|RW|RWX)\n",
        "   --add=\"zone,<servername>+<zonename>,<mode>\"\n",
        "                                         add zone (mode=R|RW|RWX)\n",
        "   --add=\"net,<servername>+<net>\"        add net (CIDR)\n",
        "   --add=\"hostmask,<regex>\"              add global hostname mask\n",
        "   --add=\"hostmask,<servername>+<zonename>,<regex>\"\n",
        "                                         add zone-bound hostname mask\n",
        "   --add=\"ipmask,<ipmask>\"               add IP-mask\n",
        "   --add=\"level,<level>\"                 add priv.level\n",
        "   --add=\"elimit,<days>\"                 add expiration limit\n",
        "   --add=\"def_dept,<string>\"             add default dept for hosts\n",
        "   --add=\"tmplmask,<regex>\"              add Template-mask\n",
        "   --add=\"grpmask,<regex>\"               add Group-mask\n",
        "   --add=\"delmask,<regex>\"               add global Host delete mask\n",
        "   --add=\"delmask,<servername>+<zonename>,<regex>\"\n",
        "                                         add zone-bound delete mask\n",
        "   --add=\"rhf,<field>=0|1\"               add RequiredHostField-setting\n",
	"   --add=\"flag,<name>\"                   add Privilege flag:\n",
        "                                            CNAME,SCNAME,AREC,MX,DELEG,\n",
        "                                            DHCP,PRINTER,SRV,RESERV\n",
        "   --del=<id>                            delete rule by id\n",
        "   --delall                              delete all rules\n",
        "\n";
  print "" if ($opt_help);
  exit(0);
}

$opt_lock = ($opt_lock ? 1 : 0);
$opt_unlock = ($opt_unlock ? 1 : 0);
$opt_edit = ($opt_edit ? 1 : 0);

db_connect();
db_debug(0);

if ($opt_list) {
  if ($modgroup) {
    print "Name                                     Comments\n";
    print "---------------------------------------- ----------------------\n";
    undef @q;
    db_query("SELECT id,name,comment FROM user_groups ORDER BY name;",\@q);
    for $i (0..$#q) {
      printf "%-40s %-20s\n", $q[$i][1],$q[$i][2];
    }
  }
  else {
    print 
     "Login      Group      Name                      Email                  Superusr\n",
     "---------- ---------- ------------------------- ---------------------- --------\n";
    undef @q;
    db_query("SELECT id,username,name,superuser,comment,email FROM users ".
	     "ORDER BY username;",\@q);
    for $i (0..$#q) {
      db_query("SELECT g.name FROM user_groups g, user_rights r " .
               "WHERE g.id=r.rref AND r.rtype=0 AND r.type=2 AND " .
	       " r.ref=$q[$i][0] ORDER BY g.id",\@qq);
      $group=substr($qq[0][0],0,10);
      printf "%-10s %-10s %-25s %-25s %-5s\n", 
              $q[$i][1],$group,substr($q[$i][2],0,25),
	      substr($q[$i][5],0,25),($q[$i][3] =~ /^(t|1)$/ ? 'Yes' : '');
    }
  }

  exit 0;
}

fatal("Invalid $fooname '$opt_user'!") unless ($opt_user =~ /^\S+$/);

if ($modgroup) {
  undef @q;
  db_query("SELECT id,comment FROM user_groups " .
	   "WHERE name='$opt_user';",\@q);
  fatal("Cannot find usergroup '$opt_user' from user_groups table!") 
    if (@q < 1);

  $id=$q[0][0];
  $utype=1;

  print "\n Groupname: $opt_user (id=$id)\n",
        "   Comment: $q[0][1]\n\n";

} else {
  undef @q;
  db_query("SELECT id,name,superuser,comment,password FROM users " .
	   "WHERE username='$opt_user';",\@q);
  fatal("Cannot find user '$opt_user' from users table!") if (@q < 1);

  $id=$q[0][0];
  $pwd=$q[0][4];
  $utype=2;

  if ($opt_name) {
    $res=db_exec("UPDATE users SET name='$opt_name', " .
		 " muser='$user',mdate='$mdate' WHERE id=$id;");
    fatal("Cannot update user description!") if ($res < 0);
    print "User description successfully updated.\n";
  }
  if ($opt_email) {
    $res=db_exec("UPDATE users SET email='$opt_email', " .
		 " muser='$user',mdate='$mdate' WHERE id=$id;");
    fatal("Cannot update user email!") if ($res < 0);
    print "User email successfully updated.\n";
  }
  if ($opt_comment) {
    $res=db_exec("UPDATE users SET comment='$opt_comment', " .
		 " muser='$user',mdate='$mdate' WHERE id=$id;");
    fatal("Cannot update user comment!") if ($res < 0);
    print "User comment successfully updated.\n";
  }

  if ($opt_expiration) {
      unless ($opt_expiration =~ /^(\d{1,2})-(\d{1,2})-(\d\d\d\d)$/) {
	  if ($opt_expiration eq 'NONE') {
	      $edate=0;
	  } else {
	      fatal("Invalid date supplied for option --expiration");
	  }
      } else {
	  $edate=timelocal(0,0,0,$1,$2-1,$3-1900);
      }

      $res=db_exec("UPDATE users SET expiration=$edate, " .
		   " muser='$user',mdate='$mdate' WHERE id=$id;");
      fatal("Cannot update user account expiration!") if ($res < 0);
      print "User account expiration successfully updated.\n";
  }

  if ($opt_superuser) {
    if ($opt_superuser eq 'yes') { $superuser='true'; }
    elsif ($opt_superuser eq 'no') { $superuser='false'; }
    else { fatal("Invalid argument to option superuser!"); }
    $res=db_exec("UPDATE users SET superuser=$superuser, " .
		 "muser='$user',mdate='$mdate' WHERE id=$id;");
    fatal("Cannot update user superuser status!") if ($res < 0);
    print "User superuser status successfully updated.\n";
  }

  if (defined $opt_passwd) {
    fatal("Account currently locked!") if ($pwd =~ /^LOCKED/);

    unless ($opt_passwd) {
      print "Enter password: ";
      chomp ($opt_passwd = <STDIN>);
    }

    $pwd=pwd_make($opt_passwd,$SAURON_PWD_MODE);
    $res=db_exec("UPDATE users SET password='$pwd', " .
		 " muser='$user', mdate='$mdate', last_pwd='$mdate' " .
		 "WHERE id=$id;");
    fatal("Cannot update user password!") if ($res < 0);
    print "User password successfully updated.\n";
  }

  if ($opt_lock) {
    if ($pwd =~ /^LOCKED/) {  fatal("account already locked!"); }
    $pwd="LOCKED:$pwd";
    $res=db_exec("UPDATE users SET password='$pwd', " .
		 " muser='$user',mdate='$mdate' WHERE id=$id;");
    fatal("Cannot update user password!") if ($res < 0);
    print "User account successfully locked.\n";
  }

  if ($opt_unlock) {
    unless ($pwd =~ /^LOCKED/) {  fatal("account not locked!"); }
    $pwd =~ s/^LOCKED://g;
    $res=db_exec("UPDATE users SET password='$pwd', " .
		 " muser='$user',mdate='$mdate' WHERE id=$id;");
    fatal("Cannot update user password!") if ($res < 0);
    print "User account successfully unlocked.\n";
  }


  undef @q;
  db_query("SELECT u.id,u.name,u.superuser,u.comment,u.password,-1, " .
	   " u.cdate,u.cuser,u.mdate,u.muser,u.expiration,u.email, ".
	   " u.last_from,u.last,u.last_pwd " .
	   "FROM users u " .
	   "WHERE u.username='$opt_user';",\@q);
  fatal("Cannot find user '$opt_user' from users table!") if (@q < 1);

  $status=($pwd=~/^LOCKED/?"LOCKED!":"valid");
    if ($pwd =~ /^(LOCKED|MD5|CRYPT|UNIX-MD5)/) {
      $status="valid ($1)";
    } else {
      $status="Invalid password" ;
    }
  $status .= ($q[0][14] > 0 ? ' (last changed '.localtime($q[0][14]).')' : '');

  $cdate_str=($q[0][6] > 0 ? localtime($q[0][6])." by $q[0][7]" : '<never>');
  $mdate_str=($q[0][8] > 0 ? localtime($q[0][8])." by $q[0][9]" : '<never>');
  $edate_str=($q[0][10] > 0 ? localtime($q[0][10])."" : '<never>');
  $longname=$q[0][1];
  $comment=$q[0][3];
  $email=$q[0][11];
  $last_from=($q[0][13] > 0 ? localtime($q[0][13])." from $q[0][12]" : '');

  db_query("SELECT g.id,g.name,r.id FROM user_groups g, user_rights r " .
	   "WHERE g.id=r.rref AND r.rtype=0 AND r.type=2 AND " .
	   " r.ref=$id ORDER BY g.id",\@groups);
  $groupnames='';
  for $i (0..$#groups) {
    $groupnames.=", " if ($groupnames);
    $groupnames.=$groups[$i][1];
  }

  print "\n           Username: $opt_user (id=$id)\n",
        "           longname: $longname\n",
        "              email: $email\n",
        "               info: $comment\n",
	"             groups: $groupnames\n",
        "          superuser: " ,($q[0][2] =~ /^(t|1)$/ ? 'Yes':'No'), "\n",
	"      passwd status: $status\n",
	"         last login: $last_from\n",
	" account expiration: $edate_str\n",
	"    account created: $cdate_str\n",
	"      last modified: $mdate_str\n\n"
	  unless (defined $opt_add || defined $opt_del || defined $opt_delall);
}



########################################

unless (defined $opt_add || defined $opt_del || defined $opt_delall) {
  print
    "ID     Type     Ref.                                         Mode\n",
    "------ -------- -------------------------------------------- ---------------------------\n";

  print "[User priviliges]\n" if ($utype == 2);
  list_privs($id,$utype);
  print "\n";

  if ($utype == 2) {
    for $i (0..$#groups) {
      printf "%-6d [Group (%s) priviliges]\n", $groups[$i][2],$groups[$i][1];
      list_privs($groups[$i][0],1);
    }
  }

  exit;
}


if (defined $opt_add) {
  unless ($opt_add) {
  add_i:
    print "Record types:\t",
      "0=", ($modgroup ? "exit" : "group"),
      ",1=server,2=zone,3=net,4=hostmask,5=IP-mask,6=priv.level\n",
      "\t\t7=elimit,8=defdept,9=Template-mask,10=Group-mask,11=Delete-mask\n",
      "\t\t12=ReqHostField,13=Flag\n",
      "Record type: ";
    chomp($type = <STDIN>);
    unless ($type ne '' && $type >= 0 && $type <=13) {
      print "invalid type!\n";
      goto add_i;
    }
    if ($type==0) {
      exit(0) if ($modgroup);
      print "Enter Group name: ";
      chomp($tmp = <STDIN>);
      db_query("SELECT id,name FROM user_groups WHERE name='$tmp';",\@d);
      if (@d < 1) { print "cannot find group: $tmp\n"; goto add_i; }
      $ref=$d[0][0];
    }
    if ($type==1 || $type==2 || $type==3) {
      print "Enter Server name : ";
      chomp($tmp = <STDIN>);
      undef @d;
      db_query("SELECT id,name FROM servers WHERE name='$tmp';",\@d);
      if (@d < 1) { print "cannot find server!\n"; goto add_i; }
      if ($type==1) {
	$mode=ask_mode(0);
	unless ($mode) { print "invalid mode!\n"; goto add_i; }
	$ref=$d[0][0];
      } else {
	$serverid=$d[0][0];
      }
    }
    if ($type==2){
      print "Enter Zone name: ";
      chomp($tmp = <STDIN>);
      undef @d;
      db_query("SELECT id,name FROM zones " .
	       "WHERE server=$serverid AND name='$tmp';",\@d);
      if (@d < 1) { print "cannot find zone!\n"; goto add_i; }
      $mode=ask_mode(0);
      unless ($mode) { print "invalid mode!\n"; goto add_i; }
      $ref=$d[0][0];
    }
    elsif ($type==3) {
      print "Enter Net (CIDR): ";
      chomp($tmp = <STDIN>);
      unless (is_cidr($tmp)) { print "Invalid CIDR!"; goto add_i; }
      undef @d;
      db_query("SELECT id,name FROM nets " .
	       "WHERE server=$serverid AND net='$tmp';",\@d);
      if (@d < 1) { print "cannot find net!\n"; goto add_i; }
      #$mode=ask_mode(1);
      $mode='unused';
      unless ($mode) { print "invalid mode!\n"; goto add_i; }
      $ref=$d[0][0];
    }
    elsif ($type==4 || $type==11) {
      print "Enter Server name (leave blank for any): ";
      chomp($tmp = <STDIN>);
      if ($tmp ne "") {
	  undef @d;
	  db_query("SELECT id,name FROM servers WHERE name='$tmp';",\@d);
	  if (@d < 1) { print "cannot find server!\n"; goto add_i; }
	  $serverid=$d[0][0];
	  print "Enter Zone name: ";
	  chomp($tmp = <STDIN>);
	  undef @d;
	  if ($tmp ne "") {
	      db_query("SELECT id,name FROM zones " .
		   "WHERE server=$serverid AND name='$tmp';",\@d);
	      if (@d < 1) { print "cannot find zone!\n"; goto add_i; }
	  }
      } else {
	  $d[0][0]=-1;
      }
      print "Enter $masktypes{$type} mask (regex): ";
      chomp($tmp = <STDIN>);
      $mode=$tmp;
      $ref=$d[0][0];
    }
    elsif ($type==9 || $type==10) {
      print "Enter $masktypes{$type} mask (regex): ";
      chomp($tmp = <STDIN>);
      $mode=$tmp;
      $ref=-1;
    }
    elsif ($type==5) {
      print "Enter IP mask (eg 192.162.1-2.*, 192.162.1-2.10-254, 2001:db8:aa-ff:1428:a*c:57ab:*): ";
      chomp($tmp = <STDIN>);
      unless (check_ipmask($tmp,'')==1) {
	  print "invalid IP-mask!\n"; goto add_i;
      }
      $mode=$tmp;
      $ref=-1;
    }
    elsif ($type==6) {
      print "Enter Privilege Level (0-999): ";
      chomp($tmp = <STDIN>);
      unless (($tmp =~ /^\d+$/) && ($tmp < 999)) {
	  print "invalid level\n"; goto add_i;
      }
      $mode=$tmp;
      $ref=-1;
    }
    elsif ($type==7) {
      print "Enter Host Expiration Limit (0-n days): ";
      chomp($tmp = <STDIN>);
      unless (($tmp =~ /^\d+$/) && ($tmp >= 0)) {
	print "invalid expiration limit\n"; goto add_i;
      }
      $mode=$tmp;
      $ref=-1;
    }
    elsif ($type==8) {
      print "Enter Default Department (string): ";
      chomp($tmp = <STDIN>);
      $tmp =~ s/^\s+|\s+$//g;
      unless (length($tmp) >= 1) {
	print "invalid default department\n"; goto add_i;
      }
      $mode=$tmp;
      $ref=-1;
    }
    elsif ($type==12) {
      print "Enter Field Name (huser,dept,location,info,ether,duid," .
	    "asset_id,model,serial,misc): ";
      chomp($tmp = <STDIN>);
      $tmp =~ s/\s+|\s+$//g;
      unless ($tmp =~ /^(huser|dept|location|info|ether|duid|asset_id|model|serial|misc)$/) {
	print "Invalid field name\n"; goto add_i;
      }
      $mode=$tmp;
      print "Enter Field Mode (0=required,1=optional): ";
      chomp($tmp = <STDIN>);
      unless ($tmp =~ /^(1|0)$/) {
	print "Invalid mode\n"; goto add_i;
      }
      $ref=$tmp;
    }
    elsif ($type==13) {
      print "Enter Privilege Flag (cname,scname,arec,mx,deleg,dhcp," .
	    "printer,srv,reserv): ";
      chomp($tmp = <STDIN>);
      $tmp =~ s/\s+|\s+$//g;
      $tmp=uc($tmp);
      unless ($tmp =~ /^(CNAME|SCNAME|AREC|MX|DELEG|GLUE|DHCP|PRINTER|SRV|RESERV)$/) {
	print "Invalid flag name\n"; goto add_i;
      }
      $mode=$tmp;
      $ref=-1;
    }

    $mode=db_encode_str($mode);
    $res=db_exec("INSERT INTO user_rights (type,ref,rtype,rref,rule) " .
		 "VALUES($utype,$id,$type,$ref,$mode);");
    fatal("cannot insert record to user_rights table!") if ($res < 0);
    exit;
  }

  fatal("invalid parameter '$opt_add' for add option!")
    unless ($opt_add =~ /^(group|server|zone|net|hostmask|ipmask|level|elimit|defdept|tmplmask|grpmask|delmask|rhf|flag),([^,\s]+)(,(\S+))?$/);
  $type=$addmodes{$1};
  $tmp=$2;
  $mode=$4;
  if ($type==0) {
    fatal("Nested groups not implemented!\n") if ($modgroup);
    undef @d;                                                                  
    db_query("SELECT id,name FROM user_groups WHERE name='$tmp';",\@d);        
    fatal("cannot find group '$tmp'") if (@d < 1);
    $ref=$d[0][0];          
  }
  if ($type==1) {
    fatal("bad mode \"$mode\"!") unless ($mode =~ /^(R|RW|RWX)$/);
    undef @d;
    db_query("SELECT id FROM servers WHERE name='$tmp';",\@d);
    fatal("cannot find server '$tmp'") if (@d < 1);
    $ref=$d[0][0];
  }
  elsif ($type==2) {
    fatal("bad mode \"$mode\"!") unless ($mode =~ /^(R|RW|RWX)$/);
    if ($tmp=~/^(\S+)\+(\S+)$/) {
      $tmp1=$1;
      $tmp2=$2;
      $serverid=get_server_id($tmp1);
      fatal("Cannot find server '$tmp1'") unless ($serverid > 0);
    } else {
      fatal("Server not specified.");
    }
    undef @d;
    db_query("SELECT id FROM zones WHERE server=$serverid AND name='$tmp2';",
	     \@d);
    fatal("cannot find zone '$tmp2'") if (@d < 1);
    $ref=$d[0][0];
  }
  elsif ($type==3) {
    fatal("bad mode \"$mode\"!") unless ($mode =~ /^$/);
    if ($tmp=~/^(\S+)\+(\S+)$/) {
      $tmp1=$1;
      $tmp2=$2;

      $serverid=get_server_id($tmp1);
      fatal("Cannot find server '$tmp1'") unless ($serverid > 0);
    } else {
      fatal("Server not specified.");
    }
    undef @d;
    db_query("SELECT id FROM nets WHERE server=$serverid AND net='$tmp2' ;",
	     \@d);
    fatal("cannot find net '$tmp'") if (@d < 1);
    $ref=$d[0][0];
    $mode="unused";
  }
  elsif ($type==4 || $type==11) {
    $mode = $tmp if ($mode =~ /^$/);
    fatal("bad mode \"$mode\"!") unless ($mode =~ /^\S+$/);
    if ($tmp=~/^(\S+)\+(\S+)$/) {
      $tmp1=$1;
      $tmp2=$2;
      $serverid=get_server_id($tmp1);
      fatal("Cannot find server '$tmp1'") unless ($serverid > 0);
      $zoneid=get_zone_id($tmp2,$serverid);
      fatal("Cannot find zone '$tmp2'") unless ($zoneid > 0);
      $ref=$zoneid;
    } else {
      $ref=-1;
    }
  } 
  elsif ($type==9 || $type==10) {
    $mode=$tmp;
    $ref=-1;
  }
  elsif ($type==5) {
    fatal("invalid IP-mask '$tmp'!")  unless (check_ipmask($tmp,'')==1);
    $mode=$tmp;
    $ref=-1;
  }
  elsif ($type==6) {
    fatal("invalid level '$tmp'!")
	unless (($tmp =~ /^\d+$/) && ($tmp < 999));
    $mode=$tmp;
    $ref=-1;
  }
  elsif ($type==7) {
    fatal("invalid expiration limit '$tmp'") unless ($tmp >= 0);
    $mode=$tmp;
    $ref=-1;
  }
  elsif ($type==8) {
    $tmp =~ s/^\s+|\s+$//g;
    fatal("invalid default department '$tmp'") unless (length($tmp) > 0);
    $mode=$tmp;
    $ref=-1;
  }
  elsif ($type==12) {
    $tmp =~ s/^\s+|\s+$//g;
    fatal("invalid field and/or mode '$tmp'")
      unless ($tmp =~ /^(huser|dept|location|info|ether|asset_id|model|serial|misc)\=(1|0)$/);
    $mode=$1;
    $ref=$2;
  }
  elsif ($type==13) {
    $tmp =~ s/^\s+|\s+$//g;
    $tmp = uc($tmp);
    fatal("invalid field and/or mode '$tmp'")
      unless ($tmp =~ /^(CNAME|SCNAME|AREC|MX|DELEG|GLUE|DHCP|PRINTER|SRV|RESERV)$/);
    $mode=$1;
    $ref=-1;
  }

  $mode=db_encode_str($mode);
  $res=db_exec("INSERT INTO user_rights (type,ref,rtype,rref,rule) " .
	       "VALUES($utype,$id,$type,$ref,$mode);");
  fatal("cannot insert record to user_rights table!") if ($res < 0);
  print "Record successfully inserted.\n";
}
elsif (defined $opt_del) {
  fatal("invalid parameter to del option!")
    unless ($opt_del =~ /^(\d+)$/);
  $tmp=$1;

  $res=db_exec("DELETE FROM user_rights " .
	       "WHERE type=$utype AND ref=$id AND id=$tmp;");
  fatal("cannot delete record (id=$tmp) from user_rights!") if ($res <1);
  printf "%s rights record successfully deleted.\n",
    ($modgroup) ? "Group" : "User";
  exit;
}
elsif ($opt_delall) {
  db_begin();
  $res=db_exec("DELETE FROM user_rights WHERE type=$utype AND ref=$id;");
  fatal("cannot delete all users records!") if ($res <1);
  fatal("commit failed!") if (db_commit()<0);
  printf "All %s rights records successfully deleted.\n",
    ($modgroup) ? "group" : "user";
}
elsif ($opt_edit) {
  fatal("option not yet implemented");
}


# eof :-)
