/************************************ */
/* Rule Set Based Access Control      */
/*                                    */
/* Author and (c) 1999-2002:          */
/* Amon Ott <ao@rsbac.org>            */
/*                                    */
/* Getname functions for Network      */
/* Last modified: 13/Mar/2002         */
/************************************ */

#include <rsbac/types.h>
#include <rsbac/getname.h>
#include <rsbac/net_getname.h>
#include <rsbac/helpers.h>
#include <rsbac/error.h>

#ifdef __KERNEL__
#include <linux/string.h>
#include <linux/module.h>
#else
#include <linux/socket.h>
#include <string.h>
#endif

static char net_temp_syscall_list[NTS_none+1][19] = {
                          "new_template",
                          "copy_template",
                          "delete_template",
                          "check_id",
                          "get_address",
                          "get_address_family",
                          "get_valid_len",
                          "get_type",
                          "get_protocol",
                          "get_netdev",
                          "get_min_port",
                          "get_max_port",
                          "get_name",
                          "set_address",
                          "set_address_family",
                          "set_valid_len",
                          "set_type",
                          "set_protocol",
                          "set_netdev",
                          "set_min_port",
                          "set_max_port",
                          "set_name",
                          "none" };

static char net_family_list[AF_MAX+1][19] = {
                      "ANY",		/* 0 */
                      "UNIX",		/* 1 Unix domain sockets */
                      "INET",		/* 2 Internet IP Protocol */
                      "AX25",		/* 3 Amateur Radio AX.25 */
                      "IPX",		/* 4 Novell IPX */
                      "APPLETALK",	/* 5 AppleTalk DDP */
                      "NETROM",		/* 6 Amateur Radio NET/ROM */
                      "BRIDGE",		/* 7 Multiprotocol bridge */
                      "ATMPVC",		/* 8 ATM PVCs */
                      "X25",		/* 9 Reserved for X.25 project */
                      "INET6",		/* 10 IP version 6 */
                      "ROSE",		/* 11 Amateur Radio X.25 PLP */
                      "DECnet",		/* 12 Reserved for DECnet project */
                      "NETBEUI",	/* 13 Reserved for 802.2LLC project */
                      "SECURITY",	/* 14 Security callback pseudo AF */
                      "KEY",		/* 15 PF_KEY key management API */
                      "NETLINK",	/* 16 */
                      "PACKET",		/* 17 Packet family */
                      "ASH",		/* 18 Ash */
                      "ECONET",		/* 19 Acorn Econet	*/
                      "ATMSVC",		/* 20 ATM SVCs */
                      "(undefined)",	/* 21 */
                      "SNA",		/* 22 Linux SNA Project (nutters!) */
                      "IRDA",		/* 23 IRDA sockets */
                      "PPPOX",		/* 24 PPPoX sockets */
                      "WANPIPE",	/* 25 Wanpipe API Sockets */
                      "(undefined)",	/* 26 */
                      "(undefined)",	/* 27 */
                      "(undefined)",	/* 28 */
                      "(undefined)",	/* 29 */
                      "(undefined)",	/* 30 */
                      "BLUETOOTH",	/* 31 Bluetooth sockets */
                      "MAX" };

struct proto_desc_t
  {
    char name[19];
    int nr;
  };
#define NR_PROTO 18

static struct proto_desc_t net_protocol_list[NR_PROTO] = {
                      {"ANY", 0},	/* 0 Dummy protocol for TCP */
                      {"ICMP", 1},	/* Internet Control Message Protocol */
                      {"IGMP", 2}, 	/* Internet Group Management Protocol	*/
                      {"IPIP", 4}, 	/* IPIP tunnels (older KA9Q tunnels use 94) */
                      {"TCP", 6},	/* Transmission Control Protocol */
                      {"EGP", 8},	/* Exterior Gateway Protocol */
                      {"PUP", 12},	/* PUP protocol */
                      {"UDP", 17},	/* User Datagram Protocol */
                      {"IDP", 22},	/* XNS IDP protocol */
                      {"RSVP", 46},	/* RSVP protocol */
                      {"GRE", 47},	/* Cisco GRE tunnels (rfc 1701,1702) */
                      {"IPV6", 41},	/* IPv6-in-IPv4 tunnelling */
                      {"PIM", 103},	/* Protocol Independent Multicast */
                      {"ESP", 50},	/* Encapsulation Security Payload protocol */
                      {"AH", 51},	/* Authentication Header protocol */
                      {"COMP", 108},	/* Compression Header protocol */
                      {"RAW", 255},	/* Raw IP packets */
                      {"MAX", RSBAC_NET_PROTO_MAX} };

static char rsbac_net_type_list[RSBAC_NET_TYPE_MAX+1][19] = {
                      "ANY",
                      "STREAM",		/* 1 stream (connection) socket */
                      "DGRAM",		/* 2 datagram (conn.less) socket */
                      "RAW",		/* 3 raw socket */
                      "RDM",		/* 4 reliably-delivered message */
                      "SEQPACKET",	/* 5 sequential packet socket */
                      "(undefined)",	/* 6 */
                      "(undefined)",	/* 7 */
                      "(undefined)",	/* 8 */
                      "(undefined)",	/* 9 */
                      "PACKET",		/* 10 linux specific way of */
					/* getting packets at the dev */
					/* level.  For writing rarp and */
					/* other similar things on the */
					/* user level. */
                      "MAX" };

/*****************************************/

char * rsbac_get_net_temp_syscall_name(char * name,
                                 enum rsbac_net_temp_syscall_t value)
  {
    if(!name)
      return(NULL);
    if(value > NTS_none)
      strcpy(name, "ERROR!");
    else
      strcpy(name, net_temp_syscall_list[value]);
    return(name);
  };

#ifndef __KERNEL__
enum rsbac_net_temp_syscall_t rsbac_get_net_temp_syscall_nr(const char * name)
  {
    enum  rsbac_net_temp_syscall_t i;

    if(!name)
      return(NTS_none);
    for (i = 0; i < NTS_none; i++)
      {
        if (!strcmp(name, net_temp_syscall_list[i]))
          {
            return(i);
          }
      }
    return(NTS_none);
  };
#endif

#ifdef __KERNEL__
#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
EXPORT_SYMBOL(rsbac_get_net_family_name);
#endif
#endif
char * rsbac_get_net_family_name(char * name,
                           u_int value)
  {
    if(!name)
      return(NULL);
    if(value > AF_MAX)
      strcpy(name, "ERROR!");
    else
      strcpy(name, net_family_list[value]);
    return(name);
  };

#ifndef __KERNEL__
int rsbac_get_net_family_nr(const char * name)
  {
    int i;

    if(!name)
      return(AF_MAX);
    for (i = 0; i < AF_MAX; i++)
      {
        if (!strcmp(name, net_family_list[i]))
          {
            return(i);
          }
      }
    return(AF_MAX);
  };
#endif

#ifdef __KERNEL__
#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
EXPORT_SYMBOL(rsbac_get_net_protocol_name);
#endif
#endif
char * rsbac_get_net_protocol_name(char * name,
                             u_int value)
  {
    int i;

    if(!name)
      return(NULL);
    if(value >= RSBAC_NET_PROTO_MAX)
      strcpy(name, "ERROR!");
    else
      {
        for (i = 0; i < NR_PROTO; i++)
          {
            if (net_protocol_list[i].nr == value)
              {
                strcpy(name, net_protocol_list[i].name);
                return name;
              }
          }
        sprintf(name, "%u", value);
      }
    return(name);
  };

#ifndef __KERNEL__
int rsbac_get_net_protocol_nr(const char * name)
  {
    int i;

    if(!name)
      return(RSBAC_NET_PROTO_MAX);
    for (i = 0; i < NR_PROTO; i++)
      {
        if (!strcmp(name, net_protocol_list[i].name))
          {
            return(net_protocol_list[i].nr);
          }
      }
    return(RSBAC_NET_PROTO_MAX);
  };
#endif

#ifdef __KERNEL__
#if defined(CONFIG_RSBAC_REG) || defined(CONFIG_RSBAC_REG_MAINT)
EXPORT_SYMBOL(rsbac_get_net_type_name);
#endif
#endif
char * rsbac_get_net_type_name(char * name,
                         u_int value)
  {
    if(!name)
      return(NULL);
    if(value > RSBAC_NET_TYPE_MAX)
      strcpy(name, "ERROR!");
    else
      strcpy(name, rsbac_net_type_list[value]);
    return(name);
  };

#ifndef __KERNEL__
int rsbac_get_net_type_nr(const char * name)
  {
    int i;

    if(!name)
      return(RSBAC_NET_TYPE_MAX);
    for (i = 0; i < RSBAC_NET_TYPE_MAX; i++)
      {
        if (!strcmp(name, rsbac_net_type_list[i]))
          {
            return(i);
          }
      }
    return(RSBAC_NET_TYPE_MAX);
  };
#endif

int rsbac_net_str_to_inet(char * str, __u32 * addr)
  {
    char * end;
    __u32 s0,s1,s2,s3;

    if(!str || !addr)
      return -RSBAC_EINVALIDPOINTER;
#ifdef __KERNEL__
    s0 = simple_strtoul(str, &end, 10);
#else
    s0 = strtoul(str, &end, 10);
#endif
    if(!*end || (s0 > 255))
      return -RSBAC_EINVALIDVALUE;
    end++;
#ifdef __KERNEL__
    s1 = simple_strtoul(end, &end, 10);
#else
    s1 = strtoul(end, &end, 10);
#endif
    if(!*end || (s1 > 255))
      return -RSBAC_EINVALIDVALUE;
    end++;
#ifdef __KERNEL__
    s2 = simple_strtoul(end, &end, 10);
#else
    s2 = strtoul(end, &end, 10);
#endif
    if(!*end || (s2 > 255))
      return -RSBAC_EINVALIDVALUE;
    end++;
#ifdef __KERNEL__
    s3 = simple_strtoul(end, &end, 10);
#else
    s3 = strtoul(end, &end, 10);
#endif
    if(*end || (s3 > 255))
      return -RSBAC_EINVALIDVALUE;
    *addr = s0 | (s1 << 8) | (s2 << 16) | (s3 << 24);
    return 0;
  }
