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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <rsbac/types.h>
#include <rsbac/getname.h>
#include <rsbac/net_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

#define SETPROG "net_temp"
#define LISTROOM 10

int verbose=0;
int backup=0;
int add=0;
rsbac_version_t version=RSBAC_API_VERSION_NR;
rsbac_list_ta_number_t ta_number = 0;
char * progname;

void use(void)
    {
      printf(gettext("%s (RSBAC %s)\n***\n"), progname, VERSION);
      printf(gettext("Use: %s [flags] function id [set-param]\n"), progname);  
      printf(gettext("     %s [flags] list_temp_{names|nr}\n"), progname);  
      printf(gettext("     %s [flags] list_template id\n"), progname);  
      printf(gettext(" -h = this help, -- = no more flags,\n"));
      printf(gettext(" -v = verbose, -l = list functions\n"));
      printf(gettext(" -b = backup mode,\n"));
      printf(gettext(" -n = take number as address, -u = take string as address,\n"));
      printf(gettext(" -d = take DNS name as address and convert to IP address,\n"));
      printf(gettext(" -A = add new addresses or ports, do not replace old list\n"));
      printf(gettext(" -a = list all templates in detail\n"));
      printf(gettext(" -V version = supply RSBAC integer version number for upgrading\n"));
      printf(gettext(" -N ta = transaction number (default = value of RSBAC_TA, if set, or 0)\n"));
    }

char * get_temp_name(rsbac_net_temp_id_t temp, char * name)
  {
    union  rsbac_net_temp_syscall_data_t data;

    if(!rsbac_net_template(ta_number, NTS_get_name, temp, &data))
      {
        strcpy(name, data.name);
      }
    else
      {
        strcpy(name, gettext("*unknown*"));
      }
    return name;
  }

void arg_exit(char * call)
  {
    fprintf(stderr, "Too few arguments for call %s\n", call);
    exit(1);
  }

void list_template(rsbac_net_temp_id_t id)
  {
    union rsbac_net_temp_syscall_data_t data;
    union rsbac_net_temp_syscall_data_t data2;
    char tmp[RSBAC_MAXNAMELEN];
    int i;

    if(verbose)
      printf("\nGetting data of template %u\n",
             id);
    else
      printf("\n");
    error_exit(rsbac_net_template(ta_number, NTS_get_name, id, &data));
    if(backup)
      {
        printf("%s -V %u new_template %u \"%s\"\n",
               SETPROG,
               RSBAC_API_VERSION_NR,
               id, data.name);
        printf("%s -V %u set_name %u \"%s\"\n",
               SETPROG,
               RSBAC_API_VERSION_NR,
               id, data.name);
      }
    else
      printf("ID:\t\t%u\nName:\t\t%s\n", id, data.name);
    error_exit(rsbac_net_template(ta_number, NTS_get_address_family, id, &data2));
    if(backup)
      printf("%s -V %u set_address_family %u %s\n",
             SETPROG,
             RSBAC_API_VERSION_NR,
             id,
             rsbac_get_net_family_name(tmp, data2.address_family));
    else
      printf("Family:\t\t%s\n",
            rsbac_get_net_family_name(tmp, data2.address_family));
    error_exit(rsbac_net_template(ta_number, NTS_get_type, id, &data));
    if(backup)
      printf("%s -V %u set_type %u %s\n",
             SETPROG,
             RSBAC_API_VERSION_NR,
             id,
             rsbac_get_net_type_name(tmp, data.type));
    else
      printf("Socket type:\t%s\n",
             rsbac_get_net_type_name(tmp, data.type));
    error_exit(rsbac_net_template(ta_number, NTS_get_address, id, &data));
    switch(data2.address_family)
      {
	case AF_INET:
		if(backup) {
			if(data.address.inet.nr_addr > 0) {
				printf("%s -V %u set_address %u",
					SETPROG,
					RSBAC_API_VERSION_NR,
					id);
				for(i=0; i<data.address.inet.nr_addr; i++) {
					printf(" %u.%u.%u.%u/%u",
					NIPQUAD(data.address.inet.addr[i]),
					data.address.inet.valid_bits[i]);
				}
				printf("\n");
			}
	        } else {
			printf("Addresses:\t");
			if(data.address.inet.nr_addr > 0) {
				for(i=0; i<data.address.inet.nr_addr; i++) {
					printf("%u.%u.%u.%u/%u ",
						NIPQUAD(data.address.inet.addr[i]),
	                                data.address.inet.valid_bits[i]);
	                        }
			}
			printf("\n");
		}
		break;
	case AF_INET6:
		if(backup) {
			if(data.address.inet6.nr_addr > 0) {
				char tmp[RSBAC_NET_MAX_ADDRESS_LEN];

				printf("%s -V %u set_address %u",
					SETPROG,
					RSBAC_API_VERSION_NR,
					id);
				for(i=0; i<data.address.inet6.nr_addr; i++) {
					printf(" %s/%u",
						inet_ntop(AF_INET6, &data.address.inet6.addr[i * RSBAC_NET_INET6_ADDR_SIZE], tmp, RSBAC_NET_MAX_ADDRESS_LEN),
						data.address.inet6.valid_bits[i]);
				}
				printf("\n");
			}
	        } else {
			printf("Addresses:\t");
			if(data.address.inet6.nr_addr > 0) {
				for(i=0; i<data.address.inet6.nr_addr; i++) {
					printf("%s/%u ",
						inet_ntop(AF_INET6, &data.address.inet6.addr[i * RSBAC_NET_INET6_ADDR_SIZE], tmp, RSBAC_NET_MAX_ADDRESS_LEN),
						data.address.inet6.valid_bits[i]);
	                        }
			}
			printf("\n");
		}
		break;
	default:
		if(!backup)
			printf("Address:\t(addresses of family %s not supported)\n",
				rsbac_get_net_family_name(tmp, data2.address_family));
      }
    error_exit(rsbac_net_template(ta_number, NTS_get_protocol, id, &data));
    switch(data2.address_family)
      {
        case AF_INET:
        case AF_INET6:
          rsbac_get_net_protocol_name(tmp, data.protocol);
          break;
        case AF_NETLINK:
          rsbac_get_netlink_protocol_name(tmp, data.protocol);
          break;
        default:
          strcpy(tmp, "ANY");
          break;
      }
    if(backup)
      printf("%s -V %u set_protocol %u %s\n",
             SETPROG,
             RSBAC_API_VERSION_NR,
             id,
             tmp);
    else
      printf("Protocol:\t%s\n",
             tmp);
    error_exit(rsbac_net_template(ta_number, NTS_get_netdev, id, &data));
    if(backup)
      printf("%s -V %u set_netdev %u \"%s\"\n",
             SETPROG,
             RSBAC_API_VERSION_NR,
             id, data.netdev);
    else
      printf("Netdev:\t\t%s\n", data.netdev);
    error_exit(rsbac_net_template(ta_number, NTS_get_ports, id, &data));
    if(backup) {
	if(data.ports.nr_ports > 0) {
		printf("%s -V %u set_ports %u",
			SETPROG,
			RSBAC_API_VERSION_NR,
			id);
		for(i=0; i<data.ports.nr_ports; i++) {
			printf(" %u:%u",
				data.ports.ports[i].min,
				data.ports.ports[i].max);
		}
		printf("\n");
	}
    } else {
	printf("Ports:\t\t");
	if(data.ports.nr_ports > 0) {
		for(i=0; i<data.ports.nr_ports; i++) {
			printf("%u:%u ",
				data.ports.ports[i].min,
				data.ports.ports[i].max);
		}
	}
	printf("\n");
    }
    return;
  }

int main(int argc, char ** argv)
{
  int res = 0;
  int i;
  int numerical=0;
  int dnsname=0;
  int listall=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 'n':
                numerical=1;
                break;
              case 'd':
                dnsname=1;
                break;
              case 's':
                break;
              case 'l':
                {
                  char tmp[RSBAC_MAXNAMELEN];

                  for(i=0; i< NTS_none ; i++)
                    printf("%s\n",
                           rsbac_get_net_temp_syscall_name(tmp, i));
                  exit(0);
                }
	      case 'L':
                if(argc > 2) {
			rsbac_net_temp_id_t id;

			for(i=2 ; i< argc ; i++) {
				id = strtoul(argv[i],0,10);
				if(id)
					list_template(id);
				else
					show_error(-RSBAC_EINVALIDTARGET);
			}
			exit(0);
		} else {
			fprintf(stderr, gettext("%s: missing transaction number value for parameter %c\n"), progname, *pos);
			exit(1);
		}
              case 'a':
                listall=1;
                break;
              case 'A':
                add=1;
                break;
              case 'V':
                if(argc < 3)
                  {
                    fprintf(stderr, gettext("%s: no version number for switch V\n"), progname);
                    exit(1);
                  }
                version = strtol(argv[2],0,10);
                argv++;
                argc--;
                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 == 2)
     && (   !strcmp(argv[1], "list_temp_names")
         || !strcmp(argv[1], "list_temp_nr")
        )
    )
    {
      rsbac_net_temp_id_t * temp_array;
      union rsbac_net_temp_syscall_data_t data;
      long count;
      int show_names = 0;
      int j;

      if(!strcmp(argv[1], "list_temp_names"))
        show_names = 1;
      count = rsbac_net_list_all_template(ta_number, NULL, 0);
      error_exit(count);
      count += LISTROOM;
      temp_array = malloc(count * sizeof(*temp_array));
      if(!temp_array)
        error_exit(-ENOMEM);
      count = rsbac_net_list_all_template(ta_number, temp_array, count);
      for(i = 0; i< count ; i++)
        {
          if(show_names)
            {
              res = rsbac_net_template(ta_number, NTS_get_name, temp_array[i], &data);
              if(!res)
                {
                  for(j=0; j<strlen(data.name); j++)
                    if(data.name[j] == ' ')
                      data.name[j] = '_';
                  printf("%u %s\n", temp_array[i], data.name);
                }
            }
          else
            printf("%u\n", temp_array[i]);
        }
      free(temp_array);
    }
  else
  if(   (   (argc >= 3)
         && !strcmp(argv[1], "list_template")
        )
     || (listall)
    )
    {
      if(listall)
        {
          rsbac_net_temp_id_t * temp_array;
          long count;

          count = rsbac_net_list_all_template(ta_number, NULL, 0);
          error_exit(count);
          count += LISTROOM;
          temp_array = malloc(count * sizeof(*temp_array));
          if(!temp_array)
            error_exit(-ENOMEM);
          count = rsbac_net_list_all_template(ta_number, temp_array, count);
          for(i = 0; i< count ; i++)
            list_template(temp_array[i]);
          free(temp_array);
        }
      else
        {
          rsbac_net_temp_id_t id;

          for(i=2 ; i< argc ; i++)
            {
              id = strtoul(argv[i],0,10);
              if(id)
                list_template(id);
              else
                show_error(-RSBAC_EINVALIDTARGET);
            }
        }
      exit(0);
    }
  else
  if(argc > 2)
    {
      enum  rsbac_net_temp_syscall_t call;
            rsbac_net_temp_id_t id;
      union rsbac_net_temp_syscall_data_t data;
      char tmp[RSBAC_MAXNAMELEN];

      call = rsbac_get_net_temp_syscall_nr(argv[1]);
      id = strtoul(argv[2],0,10);
      if(!id)
        error_exit(-RSBAC_EINVALIDTARGET);
      switch(call)
        {
          case NTS_set_address:
            if(argc > 2)
              {
		int i;
		char * pos;
		int offset = 0;
		__u8 address_family;

		error_exit(rsbac_net_template(ta_number, NTS_get_address_family, id, &data));
		address_family = data.address_family;

		if (address_family == AF_INET) {
			if(add) {
				error_exit(rsbac_net_template(ta_number, NTS_get_address, id, &data));
				offset = data.address.inet.nr_addr;
			}
	                for(i=3 ; (i < argc) && (offset + i < RSBAC_NET_NR_INET_ADDR + 3); i++) {
				pos = argv[i];
				if(!*pos || (*pos == '/')) {
					fprintf(stderr, gettext("Invalid Address %s\n"),
						pos);
					error_exit(-RSBAC_EINVALIDVALUE);
				}
				while(*pos && (*pos != '/'))
					pos++;
				if(*pos) {
					*pos = 0;
					pos++;
					if(!*pos || (*pos == '/')) {
						fprintf(stderr, gettext("Invalid Address %s\n"),
							pos);
						error_exit(-RSBAC_EINVALIDVALUE);
					}
					data.address.inet.valid_bits[offset + i-3] = strtoul(pos,0,0);
				} else
					data.address.inet.valid_bits[offset + i-3] = 32;
				if(numerical)
					data.address.inet.addr[offset + i-3] = strtoul(argv[i],0,0);
				else if(dnsname) {
					struct hostent * host;
					struct in_addr * addr_p;

					host = gethostbyname2(argv[i], AF_INET);
					if(!host) {
						fprintf(stderr, gettext("DNS lookup of address %s failed!\n"), argv[i]);
						error_exit(-RSBAC_ENOTFOUND);
					}
					addr_p = (struct in_addr *) host->h_addr;
					data.address.inet.addr[offset + i-3] = addr_p->s_addr;
	 			} else {
					struct in_addr addr;

					error_exit(inet_aton(argv[i], &addr));
					data.address.inet.addr[offset + i-3] = addr.s_addr;
				}
				if(verbose)
					printf("Adding IPv4 address %u.%u.%u.%u/%u for template %u\n",
						NIPQUAD(data.address.inet.addr[offset + i-3]),
						data.address.inet.valid_bits[offset + i-3],
						id);
			}
			if(verbose) {
				int j;

				printf("Setting %u IPv4 addresses for template %u:", offset + i-3, id);
				for(j=0; j < offset + i-3; j++)
					printf(" %u.%u.%u.%u/%u",
						NIPQUAD(data.address.inet.addr[j]),
						data.address.inet.valid_bits[j]);
				printf("\n");
			}
			data.address.inet.nr_addr = offset + i-3;
		} else if (address_family == AF_INET6) {
			char tmp[RSBAC_NET_MAX_ADDRESS_LEN];
			if(add) {
				error_exit(rsbac_net_template(ta_number, NTS_get_address, id, &data));
				offset = data.address.inet6.nr_addr;
			}
	                for(i=3 ; (i < argc) && (offset + i < RSBAC_NET_NR_INET6_ADDR + 3); i++) {
				pos = argv[i];
				if(!*pos || (*pos == '/')) {
					fprintf(stderr, gettext("Invalid Address %s\n"),
						pos);
					error_exit(-RSBAC_EINVALIDVALUE);
				}
				while(*pos && (*pos != '/'))
					pos++;
				if(*pos) {
					*pos = 0;
					pos++;
					if(!*pos || (*pos == '/')) {
						fprintf(stderr, gettext("Invalid Address %s\n"),
							pos);
						error_exit(-RSBAC_EINVALIDVALUE);
					}
					data.address.inet6.valid_bits[offset + i-3] = strtoul(pos,0,0);
				} else
					data.address.inet6.valid_bits[offset + i-3] = 128;
				if(dnsname) {
					struct hostent * host;

					host = gethostbyname2(argv[i], AF_INET6);
					if(!host) {
						fprintf(stderr, gettext("DNS lookup of address %s failed!\n"), argv[i]);
						error_exit(-RSBAC_ENOTFOUND);
					}
					if (host->h_length != RSBAC_NET_INET6_ADDR_SIZE) {
						fprintf(stderr, gettext("host->h_length %u != RSBAC_NET_INET6_ADDR_SIZE %u\n"), host->h_length, RSBAC_NET_INET6_ADDR_SIZE);
						exit(1);
					}
					memcpy(&data.address.inet6.addr[(offset + i-3) * RSBAC_NET_INET6_ADDR_SIZE], host->h_addr, RSBAC_NET_INET6_ADDR_SIZE);
	 			} else {
					__u8 addr[RSBAC_NET_INET6_ADDR_SIZE];

					if (inet_pton(AF_INET6, argv[i], &addr) <= 0) {
						fprintf(stderr, "invalid INET6/IPv6 addresse %s\n", argv[i]);
						exit(1);
					}
					memcpy(&data.address.inet6.addr[(offset + i-3) * RSBAC_NET_INET6_ADDR_SIZE], addr, RSBAC_NET_INET6_ADDR_SIZE);
				}
				if(verbose)
					printf("Adding IPv6 address %s/%u for template %u\n",
						inet_ntop(AF_INET6, &data.address.inet6.addr[(offset + i-3) * RSBAC_NET_INET6_ADDR_SIZE], tmp, RSBAC_NET_MAX_ADDRESS_LEN),
						data.address.inet6.valid_bits[offset + i-3],
						id);
			}
			data.address.inet6.nr_addr = offset + i-3;
			if(verbose) {
				int j;

				printf("Setting %u IPv6 addresses for template %u:", offset + i-3, id);
				for(j=0; j < data.address.inet6.nr_addr; j++)
					printf(" %s/%u",
						inet_ntop(AF_INET6, &data.address.inet6.addr[j * RSBAC_NET_INET6_ADDR_SIZE], tmp, RSBAC_NET_MAX_ADDRESS_LEN),
						data.address.inet6.valid_bits[j]);
				printf("\n");
			}
		} else {
			fprintf(stderr, "can only set addresses for INET and INET6\n");
			exit(1);
		}
              }
            else
              arg_exit(argv[1]);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_set_address_family:
            if(argc > 3)
              {
                data.address_family = rsbac_get_net_family_nr(argv[3]);
                if(data.address_family == AF_MAX)
                  data.address_family = strtoul(argv[3],0,10);
              }
            else
              arg_exit(argv[1]);
            if(verbose)
              printf("Setting address_family for template %u to %u (%s)\n",
                     id,
                     data.address_family,
                     rsbac_get_net_family_name(tmp, data.address_family));
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_set_type:
            if(argc > 3)
              {
                data.type = rsbac_get_net_type_nr(argv[3]);
                if(data.type == RSBAC_NET_TYPE_MAX)
                  data.type = strtoul(argv[3],0,10);
              }
            else
              arg_exit(argv[1]);
            if(verbose)
              printf("Setting socket type for template %u to %u (%s)\n",
                     id,
                     data.type,
                     rsbac_get_net_type_name(tmp, data.type));
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_set_protocol:
            if(argc > 3)
              {
                u_int proto;
                proto = rsbac_get_net_protocol_nr(argv[3]);
                if(proto == RSBAC_NET_PROTO_MAX)
                  proto = rsbac_get_netlink_protocol_nr(argv[3]);
                if(proto == RSBAC_NET_PROTO_MAX)
                  proto = strtoul(argv[3],0,10);
                if(proto >= RSBAC_NET_PROTO_MAX)
                  error_exit(-RSBAC_EINVALIDVALUE);
                data.protocol = proto;
              }
            else
              arg_exit(argv[1]);
            if(verbose)
              printf("Setting protocol for template %u to %u (%s)\n",
                     id,
                     data.protocol,
                     rsbac_get_net_protocol_name(tmp, data.protocol));
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_set_netdev:
            if(argc > 3)
              {
                strncpy((char *)data.netdev, argv[3], RSBAC_IFNAMSIZ);
                data.netdev[RSBAC_IFNAMSIZ] = 0;
              }
            else
              arg_exit(argv[1]);
            if(verbose)
              printf("Setting netdev for template %u to %s\n",
                     id, data.netdev);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_set_ports:
            if(argc > 2) {
		int i;
		char * pos;
		int offset = 0;

		if(add) {
			error_exit(rsbac_net_template(ta_number, NTS_get_ports, id, &data));
			offset = data.ports.nr_ports;
		}
                for(i=3 ; (i < argc) && (offset + i < RSBAC_NET_NR_PORTS + 3); i++) {
			pos = argv[i];
			if(!*pos || (*pos == ':')) {
				fprintf(stderr, "Invalid Port %s\n",
					pos);
				error_exit(-RSBAC_EINVALIDVALUE);
			}
			while(*pos && (*pos != ':'))
				pos++;
			if(*pos) {
				*pos = 0;
				pos++;
				data.ports.ports[offset+i-3].min = strtoul(argv[i],0,0);
				if(*pos) {
					data.ports.ports[offset+i-3].max = strtoul(pos,0,0);
					if(data.ports.ports[offset+i-3].max < data.ports.ports[offset+i-3].min)
						error_exit(-RSBAC_EINVALIDVALUE);
				}
				else
					data.ports.ports[offset+i-3].max = data.ports.ports[offset+i-3].min;
			} else {
				data.ports.ports[offset+i-3].min = strtoul(argv[i],0,0);
				data.ports.ports[offset+i-3].max = data.ports.ports[offset+i-3].min;
			}
			if(verbose)
				printf("Adding port range %u:%u for template %u\n",
					data.ports.ports[offset+i-3].min,
					data.ports.ports[offset+i-3].max,
					id);
		}
		if(verbose) {
			int j;

			printf("Setting %u port ranges for template %u:", offset+i-3, id);
			for(j=0; j<offset+i-3; j++)
				printf(" %u:%u",
					data.ports.ports[j].min,
					data.ports.ports[j].max);
			printf("\n");
		}
		data.ports.nr_ports = offset+i-3;
	    }
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_set_name:
            if(argc > 3)
              {
                strncpy(data.name, argv[3], RSBAC_NET_TEMP_NAMELEN-1);
                data.name[RSBAC_NET_TEMP_NAMELEN-1] = 0;
              }
            else
              arg_exit(argv[1]);
            if(verbose)
              printf("Setting name for template %u to %s\n",
                     id, data.name);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_new_template:
            if(argc > 3)
              {
                strncpy(data.name, argv[3], RSBAC_NET_TEMP_NAMELEN-1);
                data.name[RSBAC_NET_TEMP_NAMELEN-1] = 0;
              }
            else
              strcpy(data.name, "(unknown)");
            if(verbose)
              printf("Creating template %u with name %s\n",
                     id, data.name);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_copy_template:
            if(argc > 3)
              data.id = strtoul(argv[3],0,10);
            else
              arg_exit(argv[1]);
            if(verbose)
              printf("Copying template %u from template %u\n",
                     id, data.id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_delete_template:
            if(verbose)
              printf("Deleting template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            exit(0);
          case NTS_check_id:
            if(verbose)
              printf("Checking for template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            printf("%u\n", data.id);
            exit(0);
          case NTS_get_address:
            {
              union rsbac_net_temp_syscall_data_t data2;

              if(verbose)
                printf("Getting address of template %u\n",
                       id);
              error_exit(rsbac_net_template(ta_number, call, id, &data));
              error_exit(rsbac_net_template(ta_number, NTS_get_address_family, id, &data2));
              switch(data2.address_family)
                {
                  case AF_INET:
		    if(data.address.inet.nr_addr > 0) {
			int i;

			for(i=0; i < data.address.inet.nr_addr; i++)
				printf("%u.%u.%u.%u/%u ",
					NIPQUAD(data.address.inet.addr[i]),
					data.address.inet.valid_bits[i]);
			printf("\n");
		    }
                    break;
                  case AF_INET6:
		    if(data.address.inet6.nr_addr > 0) {
			int i;
			char tmp[RSBAC_NET_MAX_ADDRESS_LEN];

			for(i=0; i < data.address.inet6.nr_addr; i++)
				printf("%s/%u ",
					inet_ntop(AF_INET6, &data.address.inet6.addr[i * RSBAC_NET_INET6_ADDR_SIZE], tmp, RSBAC_NET_MAX_ADDRESS_LEN),
					data.address.inet6.valid_bits[i]);
			printf("\n");
		    }
                    break;
                  default:
                    printf("(address family not supported)\n");
                }
              exit(0);
            }
          case NTS_get_address_family:
            if(verbose)
              printf("Getting address_family of template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            printf("%s\n",
                   rsbac_get_net_family_name(tmp, data.address_family));
            exit(0);
          case NTS_get_type:
            if(verbose)
              printf("Getting socket type of template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            printf("%s\n",
                   rsbac_get_net_type_name(tmp, data.type));
            exit(0);
          case NTS_get_protocol:
            {
              union rsbac_net_temp_syscall_data_t data2;

              if(verbose)
                printf("Getting protocol of template %u\n",
                       id);
              error_exit(rsbac_net_template(ta_number, call, id, &data));
              error_exit(rsbac_net_template(ta_number, NTS_get_address_family, id, &data2));
              switch(data2.address_family)
                {
                  case AF_INET:
                  case AF_INET6:
                    printf("%s\n",
                           rsbac_get_net_protocol_name(tmp, data.protocol));
                    break;
                  case AF_NETLINK:
                    printf("%s\n",
                           rsbac_get_netlink_protocol_name(tmp, data.protocol));
                    break;
                  default:
                    printf("(address family not supported)\n");
                }
              exit(0);
            }
          case NTS_get_netdev:
            if(verbose)
              printf("Getting netdev of template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            printf("%s\n", data.netdev);
            exit(0);
          case NTS_get_ports:
            if(verbose)
              printf("Getting port ranges of template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            if(data.ports.nr_ports > 0) {
		int i;

		for(i=0; i < data.ports.nr_ports; i++)
			printf("%u:%u ",
				data.ports.ports[i].min,
				data.ports.ports[i].max);
		printf("\n");
	    }
            exit(0);
          case NTS_get_name:
            if(verbose)
              printf("Getting name of template %u\n",
                     id);
            error_exit(rsbac_net_template(ta_number, call, id, &data));
            printf("%s\n", data.name);
            exit(0);

          default:
            if((argc > 3) && !strcmp(argv[1], "set_min_port")) {
		error_exit(rsbac_net_template(ta_number, NTS_get_ports, id, &data));
		if(data.ports.nr_ports > 0) {
			data.ports.ports[0].min = strtoul(argv[3],0,0);
		} else {
			data.ports.ports[0].min = strtoul(argv[3],0,0);
			data.ports.ports[0].max = data.ports.ports[0].min;
			data.ports.nr_ports = 1;
		}
		if(verbose) {
			int j;

			printf("Setting %u port ranges for template %u:", data.ports.nr_ports, id);
			for(j=0; j<data.ports.nr_ports; j++)
				printf(" %u:%u",
					data.ports.ports[j].min,
					data.ports.ports[j].max);
			printf("\n");
		}
		error_exit(rsbac_net_template(ta_number, NTS_set_ports, id, &data));
            } else if((argc > 3) && !strcmp(argv[1], "set_max_port")) {
		error_exit(rsbac_net_template(ta_number, NTS_get_ports, id, &data));
		if(data.ports.nr_ports > 0) {
			data.ports.ports[0].max = strtoul(argv[3],0,0);
		} else {
			data.ports.ports[0].min = strtoul(argv[3],0,0);
			data.ports.ports[0].max = data.ports.ports[0].min;
			data.ports.nr_ports = 1;
		}
		if(verbose) {
			int j;

			printf("Setting %u port ranges for template %u:", data.ports.nr_ports, id);
			for(j=0; j<data.ports.nr_ports; j++)
				printf(" %u:%u",
					data.ports.ports[j].min,
					data.ports.ports[j].max);
			printf("\n");
		}
		error_exit(rsbac_net_template(ta_number, NTS_set_ports, id, &data));
            } else if((argc > 3) && !strcmp(argv[1], "set_valid_len")) {
		error_exit(rsbac_net_template(ta_number, NTS_get_address_family, id, &data));
		if(data.address_family == AF_INET) {
			error_exit(rsbac_net_template(ta_number, NTS_get_address, id, &data));
			if(data.address.inet.nr_addr > 0) {
				data.address.inet.valid_bits[0] = strtoul(argv[3],0,0);
				error_exit(rsbac_net_template(ta_number, NTS_set_address, id, &data));
			}
		}
		else if(data.address_family == AF_INET6) {
			error_exit(rsbac_net_template(ta_number, NTS_get_address, id, &data));
			if(data.address.inet6.nr_addr > 0) {
				data.address.inet6.valid_bits[0] = strtoul(argv[3],0,0);
				error_exit(rsbac_net_template(ta_number, NTS_set_address, id, &data));
			}
		}
            } else {
		fprintf(stderr, "Invalid call %s!\n", argv[1]);
		exit(1);
	    }
        }
      exit(0);
    }
  else
    {
      use();
      return 1;
    }
  exit(0);
}

