lkml.org 
[lkml]   [2007]   [Oct]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[TOMOYO 09/15](repost) Networking access control functions.
    Network access control functions for TOMOYO Linux.
    TOMOYO Linux checks permission by the following four parameters.
    * protocol type (TCP, UDP, RAW)
    * access type (bind, listen, connect, accept)
    * IP address (Both IPv4 and IPv6 are available)
    * port number
    In order to check 'TCP accept' and 'UDP connect',
    LSM expansion patch ([TOMOYO 14/15]) is needed.

    Each permission can be automatically accumulated into
    the policy of each domain using 'learning mode'.

    Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
    Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    ---
    security/tomoyo/net.c | 975 ++++++++++++++++++++++++++++++++++++++++++++++++++
    1 files changed, 975 insertions(+)

    --- /dev/null 1970-01-01 00:00:00.000000000 +0000
    +++ linux-2.6/security/tomoyo/net.c 2007-10-02 11:26:22.000000000 +0900
    @@ -0,0 +1,975 @@
    +/*
    + * security/tomoyo/net.c
    + *
    + * Network access control functions for TOMOYO Linux.
    + */
    +
    +#include "tomoyo.h"
    +#include "realpath.h"
    +#include <net/ip.h>
    +
    +/************************* AUDIT FUNCTIONS *************************/
    +
    +static int tmy_audit_network_log(const u8 is_ipv6,
    + const char *operation,
    + const u32 *address,
    + const u16 port,
    + const u8 is_granted,
    + const u8 is_enforce)
    +{
    + char *buf;
    + int len = 256;
    +
    + if (is_granted) {
    + if (!tmy_audit_grant())
    + return 0;
    + } else {
    + if (!tmy_audit_reject())
    + return 0;
    + }
    +
    + buf = tmy_init_audit_log(&len);
    + if (!buf)
    + return -ENOMEM;
    +
    + snprintf(buf + strlen(buf), len - strlen(buf) - 1,
    + TMY_ALLOW_NETWORK "%s ", operation);
    +
    + if (is_ipv6)
    + tmy_print_ipv6(buf + strlen(buf), len - strlen(buf),
    + (const u16 *) address);
    + else {
    + u32 ip = *address;
    + snprintf(buf + strlen(buf), len - strlen(buf) - 1,
    + NIPQUAD_FMT, NIPQUAD(ip));
    + }
    +
    + snprintf(buf + strlen(buf), len - strlen(buf) - 1, " %u", port);
    +
    + return tmy_write_audit_log(buf, is_granted, is_enforce);
    +}
    +
    +/************************* ADDRESS GROUP HANDLER *************************/
    +
    +/* List of address group. */
    +static struct addr_group_entry *group_list;
    +
    +static int tmy_add_addr_group_entry(const char *group_name,
    + const u8 is_ipv6,
    + const u16 *min_address,
    + const u16 *max_address,
    + const u8 is_delete)
    +{
    + static DECLARE_MUTEX(lock);
    + struct addr_group_entry *new_group;
    + struct addr_group_entry *group;
    + struct addr_group_member *new_member;
    + struct addr_group_member *member;
    + const struct path_info *saved_group_name;
    + int error = -ENOMEM;
    +
    + if (!tmy_correct_path(group_name, 0, 0, 0, __FUNCTION__) ||
    + !group_name[0])
    + return -EINVAL;
    +
    + saved_group_name = tmy_save_name(group_name);
    + if (!saved_group_name)
    + return -ENOMEM;
    +
    + down(&lock);
    +
    + for (group = group_list; group; group = group->next) {
    +
    + if (saved_group_name != group->group_name)
    + continue;
    +
    + for (member = group->first_member;
    + member;
    + member = member->next) {
    +
    + if (member->is_ipv6 != is_ipv6)
    + continue;
    +
    + if (is_ipv6) {
    + if (memcmp(member->min.ipv6, min_address, 16) ||
    + memcmp(member->max.ipv6, max_address, 16))
    + continue;
    + } else {
    + if (member->min.ipv4 != *(u32 *) min_address ||
    + member->max.ipv4 != *(u32 *) max_address)
    + continue;
    + }
    +
    + member->is_deleted = is_delete;
    + error = 0;
    + goto out;
    + }
    + break;
    + }
    +
    + if (is_delete) {
    + error = -ENOENT;
    + goto out;
    + }
    +
    + if (!group) {
    + new_group = tmy_alloc_element(sizeof(*new_group));
    + if (!new_group)
    + goto out;
    + new_group->group_name = saved_group_name;
    + mb(); /* Instead of using spinlock. */
    + group = group_list;
    + if (group) {
    + while (group->next)
    + group = group->next;
    + group->next = new_group;
    + } else
    + group_list = new_group;
    + group = new_group;
    + }
    +
    + new_member = tmy_alloc_element(sizeof(*new_member));
    + if (!new_member)
    + goto out;
    +
    + new_member->is_ipv6 = is_ipv6;
    +
    + if (is_ipv6) {
    + memmove(new_member->min.ipv6, min_address, 16);
    + memmove(new_member->max.ipv6, max_address, 16);
    + } else {
    + new_member->min.ipv4 = *(u32 *) min_address;
    + new_member->max.ipv4 = *(u32 *) max_address;
    + }
    +
    + mb(); /* Instead of using spinlock. */
    +
    + member = group->first_member;
    + if (member) {
    + while (member->next)
    + member = member->next;
    + member->next = new_member;
    + } else
    + group->first_member = new_member;
    +
    + error = 0;
    +out: ;
    + up(&lock);
    +
    + return error;
    +}
    +
    +/**
    + * tmy_add_addr_group_policy - add or delete address group policy.
    + * @data: a line to parse.
    + * @is_delete: is this delete request?
    + *
    + * Returns zero on success.
    + * Returns nonzero on failure.
    + */
    +int tmy_add_addr_group_policy(char *data, const u8 is_delete)
    +{
    + int count;
    + u8 is_ipv6;
    + u16 min_address[8];
    + u16 max_address[8];
    + unsigned int min[8];
    + unsigned int max[8];
    + char *cp = strchr(data, ' ');
    +
    + if (!cp)
    + return -EINVAL;
    +
    + *cp++ = '\0';
    + count = sscanf(cp,
    + NIP6_FMT "-" NIP6_FMT,
    + &min[0], &min[1], &min[2], &min[3],
    + &min[4], &min[5], &min[6], &min[7],
    + &max[0], &max[1], &max[2], &max[3],
    + &max[4], &max[5], &max[6], &max[7]);
    +
    + if (count == 8 || count == 16) {
    +
    + int i;
    +
    + for (i = 0; i < 8; i++) {
    + min_address[i] = htons((u16) min[i]);
    + max_address[i] = htons((u16) max[i]);
    + }
    + if (count == 8)
    + memmove(max_address, min_address, sizeof(min_address));
    + is_ipv6 = 1;
    +
    + goto ok;
    +
    + }
    +
    + count = sscanf(cp,
    + NIPQUAD_FMT "-" NIPQUAD_FMT,
    + &min[0], &min[1],
    + &min[2], &min[3],
    + &max[0], &max[1],
    + &max[2], &max[3]);
    +
    + if (count == 4 || count == 8) {
    + u32 ip = ((((u8) min[0]) << 24) +
    + (((u8) min[1]) << 16) +
    + (((u8) min[2]) << 8) +
    + (u8) min[3]);
    +
    + *(u32 *) min_address = ip;
    +
    + if (count == 8)
    + ip = ((((u8) max[0]) << 24) +
    + (((u8) max[1]) << 16) +
    + (((u8) max[2]) << 8) +
    + (u8) max[3]);
    +
    + *(u32 *) max_address = ip;
    + is_ipv6 = 0;
    +
    + goto ok;
    +
    + }
    +
    + return -EINVAL;
    +
    +ok: ;
    + return tmy_add_addr_group_entry(data, is_ipv6, min_address, max_address,
    + is_delete);
    +}
    +
    +static struct addr_group_entry *tmy_new_addr_group(const char *name)
    +{
    + int i;
    + struct addr_group_entry *group;
    +
    + for (i = 0; i <= 1; i++) {
    + for (group = group_list; group; group = group->next) {
    +
    + if (strcmp(name, group->group_name->name) == 0)
    + return group;
    +
    + }
    +
    + if (i == 0) {
    + /*
    + * Add a dummy entry to create new address group
    + * and delete that entry.
    + */
    + const u16 dum[2] = { 0, 0 };
    + tmy_add_addr_group_entry(name, 0, dum, dum, 0);
    + tmy_add_addr_group_entry(name, 0, dum, dum, 1);
    + }
    + }
    +
    + return NULL;
    +}
    +
    +static int tmy_address_match_group(const u8 is_ipv6,
    + const u32 *address,
    + const struct addr_group_entry *group)
    +{
    + struct addr_group_member *member;
    + const u32 ip = ntohl(*address);
    +
    + for (member = group->first_member; member; member = member->next) {
    +
    + if (member->is_deleted)
    + continue;
    +
    + if (member->is_ipv6) {
    +
    + if (is_ipv6 &&
    + memcmp(member->min.ipv6, address, 16) <= 0 &&
    + memcmp(address, member->max.ipv6, 16) <= 0)
    + return 1;
    +
    + } else {
    +
    + if (!is_ipv6 &&
    + member->min.ipv4 <= ip &&
    + ip <= member->max.ipv4)
    + return 1;
    +
    + }
    + }
    +
    + return 0;
    +}
    +
    +static int tmy_read_addr_group(struct io_buffer *head,
    + struct addr_group_entry *group,
    + struct addr_group_member *member)
    +{
    + char buf[128];
    + if (!member)
    + return 0;
    +
    + if (member->is_ipv6) {
    +
    + const u16 *min_addr = member->min.ipv6;
    + const u16 *max_addr = member->max.ipv6;
    +
    + tmy_print_ipv6(buf, sizeof(buf), min_addr);
    +
    + if (memcmp(min_addr, max_addr, 16)) {
    + char *cp = strchr(buf, '\0');
    + int len = sizeof(buf) - strlen(buf);
    +
    + *cp++ = '-';
    + tmy_print_ipv6(cp, len, max_addr);
    + }
    +
    + } else {
    +
    + const u32 min_addr = member->min.ipv4;
    + const u32 max_addr = member->max.ipv4;
    +
    + memset(buf, 0, sizeof(buf));
    + snprintf(buf, sizeof(buf) - 1,
    + NIPQUAD_FMT, HIPQUAD(min_addr));
    +
    + if (min_addr != max_addr) {
    + const int len = strlen(buf);
    +
    + snprintf(buf + len, sizeof(buf) - 1 - len,
    + "-" NIPQUAD_FMT, HIPQUAD(max_addr));
    + }
    +
    + }
    +
    + return tmy_io_printf(head, TMY_ADDRESS_GROUP "%s %s\n",
    + group->group_name->name, buf);
    +}
    +
    +/**
    + * tmy_read_addr_group_policy - read address group policy
    + * @head: pointer to "struct io_buffer".
    + *
    + * Returns nonzero if reading incomplete.
    + * Returns zero otherwise.
    + */
    +int tmy_read_addr_group_policy(struct io_buffer *head)
    +{
    + struct addr_group_entry *group = head->read_var1;
    + struct addr_group_member *member = head->read_var2;
    +
    + if (!group)
    + group = group_list;
    +
    + while (group) {
    + head->read_var1 = group;
    + if (!member)
    + member = group->first_member;
    + while (member) {
    +
    + head->read_var2 = member;
    + if (member->is_deleted) {
    + member = member->next;
    + continue;
    + }
    +
    + if (tmy_read_addr_group(head, group, member))
    + break;
    +
    + member = member->next;
    + }
    + if (member)
    + break;
    + head->read_var2 = NULL;
    + group = group->next;
    + }
    + return group ? -ENOMEM : 0;
    +}
    +
    +/*********************** NETWORK NETWORK ACL HANDLER ***********************/
    +
    +/**
    + * tmy_print_ipv6 - print ipv6 address
    + * @buffer: pointer to buffer to save the result.
    + * @buffer_len: sizeof @buffer .
    + * @ip: pointer to an IPv6 address in network byte order.
    + *
    + * Returns @buffer .
    + */
    +char *tmy_print_ipv6(char *buffer, const int buffer_len, const u16 *ip)
    +{
    + memset(buffer, 0, buffer_len);
    + snprintf(buffer, buffer_len - 1, NIP6_FMT,
    + ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]),
    + ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]));
    + return buffer;
    +}
    +
    +/**
    + * tmy_network2keyword - get keyword from access control index.
    + * @operation: index number.
    + *
    + * Returns keyword that corresponds with @operation .
    + */
    +const char *tmy_network2keyword(const unsigned int operation)
    +{
    + const char *keyword = "unknown";
    + switch (operation) {
    + case TMY_NETWORK_ACL_UDP_BIND:
    + keyword = "UDP bind";
    + break;
    + case TMY_NETWORK_ACL_UDP_CONNECT:
    + keyword = "UDP connect";
    + break;
    + case TMY_NETWORK_ACL_TCP_BIND:
    + keyword = "TCP bind";
    + break;
    + case TMY_NETWORK_ACL_TCP_LISTEN:
    + keyword = "TCP listen";
    + break;
    + case TMY_NETWORK_ACL_TCP_CONNECT:
    + keyword = "TCP connect";
    + break;
    + case TMY_NETWORK_ACL_TCP_ACCEPT:
    + keyword = "TCP accept";
    + break;
    + case TMY_NETWORK_ACL_RAW_BIND:
    + keyword = "RAW bind";
    + break;
    + case TMY_NETWORK_ACL_RAW_CONNECT:
    + keyword = "RAW connect";
    + break;
    + }
    + return keyword;
    +}
    +
    +/* Compare IPv4/IPv6 address. */
    +static int tmy_cmp_network_entry(const u8 record_type,
    + struct net_acl *acl,
    + const struct addr_group_entry *group,
    + const u32 min_ip,
    + const u32 max_ip,
    + const u32 *min_address,
    + const u32 *max_address)
    +{
    + int found = 0;
    +
    + switch (record_type) {
    +
    + case TMY_TYPE_ADDRESS_GROUP:
    + if (acl->u.group == group)
    + found = 1;
    + break;
    +
    + case TMY_TYPE_IPv4:
    + if (acl->u.ipv4.min == min_ip &&
    + max_ip == acl->u.ipv4.max)
    + found = 1;
    + break;
    +
    + case TMY_TYPE_IPv6:
    + if (memcmp(acl->u.ipv6.min, min_address, 16) == 0 &&
    + memcmp(max_address, acl->u.ipv6.max, 16) == 0)
    + found = 1;
    + break;
    +
    + }
    +
    + return found;
    +}
    +
    +static int tmy_add_network_entry(const u8 operation,
    + const u8 record_type,
    + const struct addr_group_entry *group,
    + const u32 *min_address,
    + const u32 *max_address,
    + const u16 min_port,
    + const u16 max_port,
    + struct domain_info *domain,
    + const struct condition_list *cond,
    + const u8 is_delete)
    +{
    + struct acl_info *ptr;
    + int error = -ENOMEM;
    + /* using host byte order to allow u32 comparison than memcmp().*/
    + const u32 min_ip = ntohl(*min_address);
    + const u32 max_ip = ntohl(*max_address);
    +
    + if (!domain)
    + return -EINVAL;
    +
    + down(&domain_acl_lock);
    +
    + if (is_delete)
    + goto remove;
    +
    + ptr = domain->first_acl_ptr;
    + if (!ptr)
    + goto first_entry;
    +
    + while (1) {
    + struct net_acl *acl = (struct net_acl *) ptr;
    +
    + if (ptr->type == TMY_TYPE_IP_NETWORK_ACL &&
    + ptr->cond == cond &&
    + acl->operation_type == operation &&
    + acl->record_type == record_type &&
    + acl->min_port == min_port &&
    + max_port == acl->max_port &&
    + tmy_cmp_network_entry(record_type, acl,
    + group, min_ip, max_ip,
    + min_address,
    + max_address)) {
    + ptr->is_deleted = 0;
    + error = 0;
    + break;
    + }
    +
    + if (ptr->next) {
    + ptr = ptr->next;
    + continue;
    + }
    +first_entry: ;
    + /* Not found. Append it to the tail. */
    + acl = tmy_alloc_element(sizeof(*acl));
    + if (!acl)
    + break;
    +
    + acl->head.type = TMY_TYPE_IP_NETWORK_ACL;
    + acl->head.cond = cond;
    + acl->operation_type = operation;
    + acl->record_type = record_type;
    +
    + if (record_type == TMY_TYPE_ADDRESS_GROUP)
    + acl->u.group = group;
    + else if (record_type == TMY_TYPE_IPv4) {
    + acl->u.ipv4.min = min_ip;
    + acl->u.ipv4.max = max_ip;
    + } else {
    + memmove(acl->u.ipv6.min, min_address, 16);
    + memmove(acl->u.ipv6.max, max_address, 16);
    + }
    +
    + acl->min_port = min_port;
    + acl->max_port = max_port;
    + error = tmy_add_acl(ptr, domain,
    + (struct acl_info *) acl);
    + break;
    + }
    + goto ok;
    +remove: ;
    + error = -ENOENT;
    + for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
    + struct net_acl *acl = (struct net_acl *) ptr;
    + if (ptr->type != TMY_TYPE_IP_NETWORK_ACL ||
    + ptr->cond != cond ||
    + ptr->is_deleted ||
    + acl->operation_type != operation ||
    + acl->record_type != record_type ||
    + acl->min_port != min_port ||
    + acl->max_port != max_port ||
    + !tmy_cmp_network_entry(record_type, acl,
    + group, min_ip, max_ip,
    + min_address,
    + max_address))
    + continue;
    +
    + error = tmy_del_acl(ptr);
    + break;
    + }
    +ok: ;
    + up(&domain_acl_lock);
    +
    + return error;
    +}
    +
    +/* Check network permission. */
    +static int tmy_network_entry(const u8 is_ipv6,
    + const int operation,
    + const u32 *address,
    + const u16 port)
    +{
    + struct domain_info * const domain = TMY_SECURITY->domain;
    + struct acl_info *ptr;
    + const char *keyword = tmy_network2keyword(operation);
    + const u8 is_enforce = tmy_enforce(TMY_MAC_FOR_NETWORK);
    + /* using host byte order to allow u32 comparison than memcmp().*/
    + const u32 ip = ntohl(*address);
    +
    + if (!tmy_flags(TMY_MAC_FOR_NETWORK))
    + return 0;
    +
    + for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {
    + struct net_acl *acl = (struct net_acl *) ptr;
    +
    + if (ptr->type != TMY_TYPE_IP_NETWORK_ACL ||
    + ptr->is_deleted ||
    + acl->operation_type != operation ||
    + port < acl->min_port ||
    + acl->max_port < port ||
    + tmy_check_condition(ptr->cond, NULL))
    + continue;
    +
    + if (acl->record_type == TMY_TYPE_ADDRESS_GROUP &&
    + tmy_address_match_group(is_ipv6, address, acl->u.group))
    + break;
    +
    + else if (acl->record_type == TMY_TYPE_IPv4 && !is_ipv6 &&
    + (acl->u.ipv4.min <= ip && ip <= acl->u.ipv4.max))
    + break;
    +
    + else if (acl->record_type == TMY_TYPE_IPv6 && is_ipv6 &&
    + memcmp(acl->u.ipv6.min, address, 16) <= 0 &&
    + memcmp(address, acl->u.ipv6.max, 16) <= 0)
    + break;
    +
    + }
    +
    + tmy_audit_network_log(is_ipv6, keyword, address,
    + port, ptr != 0, is_enforce);
    +
    + if (ptr)
    + return 0;
    +
    + if (is_enforce) {
    +
    + if (is_ipv6) {
    +
    + char buf[64];
    +
    + tmy_print_ipv6(buf, sizeof(buf), (const u16 *) address);
    + return tmy_supervisor("%s\n" TMY_ALLOW_NETWORK
    + "%s %s %u\n",
    + domain->domainname->name, keyword,
    + buf, port);
    +
    + }
    +
    + return tmy_supervisor("%s\n" TMY_ALLOW_NETWORK
    + "%s " NIPQUAD_FMT " %u\n",
    + domain->domainname->name, keyword,
    + HIPQUAD(ip), port);
    +
    + }
    +
    + if (tmy_accept(TMY_MAC_FOR_NETWORK, domain))
    + tmy_add_network_entry(operation,
    + is_ipv6 ? TMY_TYPE_IPv6 : TMY_TYPE_IPv4,
    + NULL, address, address,
    + port, port, domain, NULL, 0);
    +
    + return 0;
    +}
    +
    +/**
    + * tmy_add_signal_policy - add or delete signal policy.
    + * @data: a line to parse.
    + * @domain: pointer to "struct domain_info".
    + * @cond: pointer to "struct condition_list". May be NULL.
    + * @is_delete: is this delete request?
    + *
    + * Returns zero on success.
    + * Returns nonzero on failure.
    + */
    +int tmy_add_network_policy(char *data,
    + struct domain_info *domain,
    + const struct condition_list *cond,
    + const u8 is_delete)
    +{
    + u8 sock_type;
    + u8 operation;
    + u8 record_type;
    + u16 min_address[8];
    + u16 max_address[8];
    + unsigned int min[8];
    + unsigned int max[8];
    + struct addr_group_entry *group = NULL;
    + u16 min_port;
    + u16 max_port;
    + int count;
    + char *cp1 = NULL;
    + char *cp2 = NULL;
    +
    + cp1 = strchr(data, ' ');
    + if (!cp1)
    + goto out;
    + cp1++;
    +
    + if (strncmp(data, "TCP ", 4) == 0)
    + sock_type = SOCK_STREAM;
    + else if (strncmp(data, "UDP ", 4) == 0)
    + sock_type = SOCK_DGRAM;
    + else if (strncmp(data, "RAW ", 4) == 0)
    + sock_type = SOCK_RAW;
    + else
    + goto out;
    +
    + cp2 = strchr(cp1, ' ');
    + if (!cp2)
    + goto out;
    + cp2++;
    +
    + if (strncmp(cp1, "bind ", 5) == 0) {
    + switch (sock_type) {
    + case SOCK_STREAM:
    + operation = TMY_NETWORK_ACL_TCP_BIND;
    + break;
    + case SOCK_DGRAM:
    + operation = TMY_NETWORK_ACL_UDP_BIND;
    + break;
    + default:
    + operation = TMY_NETWORK_ACL_RAW_BIND;
    + break;
    + }
    + } else if (strncmp(cp1, "connect ", 8) == 0) {
    + switch (sock_type) {
    + case SOCK_STREAM:
    + operation = TMY_NETWORK_ACL_TCP_CONNECT;
    + break;
    + case SOCK_DGRAM:
    + operation = TMY_NETWORK_ACL_UDP_CONNECT;
    + break;
    + default:
    + operation = TMY_NETWORK_ACL_RAW_CONNECT;
    + break;
    + }
    + } else if (sock_type == SOCK_STREAM &&
    + strncmp(cp1, "listen ", 7) == 0)
    + operation = TMY_NETWORK_ACL_TCP_LISTEN;
    +
    + else if (sock_type == SOCK_STREAM &&
    + strncmp(cp1, "accept ", 7) == 0)
    + operation = TMY_NETWORK_ACL_TCP_ACCEPT;
    +
    + else
    + goto out;
    +
    + cp1 = strchr(cp2, ' ');
    + if (!cp1)
    + goto out;
    + *cp1++ = '\0';
    +
    + count = sscanf(cp2,
    + NIP6_FMT "-" NIP6_FMT,
    + &min[0], &min[1], &min[2], &min[3],
    + &min[4], &min[5], &min[6], &min[7],
    + &max[0], &max[1], &max[2], &max[3],
    + &max[4], &max[5], &max[6], &max[7]);
    +
    + if (count == 8 || count == 16) {
    +
    + int i;
    +
    + for (i = 0; i < 8; i++) {
    + min_address[i] = htons((u16) min[i]);
    + max_address[i] = htons((u16) max[i]);
    + }
    +
    + if (count == 8)
    + memmove(max_address, min_address, sizeof(min_address));
    + record_type = TMY_TYPE_IPv6;
    +
    + goto ok;
    +
    + }
    +
    + count = sscanf(cp2,
    + NIPQUAD_FMT "-" NIPQUAD_FMT,
    + &min[0], &min[1], &min[2], &min[3],
    + &max[0], &max[1], &max[2], &max[3]);
    +
    + if (count == 4 || count == 8) {
    +
    + u32 ip = htonl((((u8) min[0]) << 24) +
    + (((u8) min[1]) << 16) +
    + (((u8) min[2]) << 8) +
    + (u8) min[3]);
    + *(u32 *) min_address = ip;
    +
    + if (count == 8)
    + ip = htonl((((u8) max[0]) << 24) +
    + (((u8) max[1]) << 16) +
    + (((u8) max[2]) << 8) +
    + (u8) max[3]);
    + *(u32 *) max_address = ip;
    + record_type = TMY_TYPE_IPv4;
    +
    + goto ok;
    +
    + }
    +
    + if (*cp2 == '@') {
    +
    + group = tmy_new_addr_group(cp2 + 1);
    + if (!group)
    + return -ENOMEM;
    + record_type = TMY_TYPE_ADDRESS_GROUP;
    +
    + goto ok;
    + }
    +
    + goto out;
    +
    +ok: ;
    + if (strchr(cp1, ' '))
    + goto out;
    +
    + count = sscanf(cp1, "%hu-%hu", &min_port, &max_port);
    + if (count != 1 && count != 2)
    + goto out;
    +
    + if (count == 1)
    + max_port = min_port;
    +
    + return tmy_add_network_entry(operation, record_type, group,
    + (u32 *) min_address,
    + (u32 *) max_address,
    + min_port, max_port, domain,
    + cond, is_delete);
    +
    +out: ;
    + return -EINVAL;
    +}
    +
    +/**
    + * tmy_network_listen_acl - check permission for listen(2) operation.
    + * @is_ipv6: is @address an IPv6 address?
    + * @address: pointer to IPv4/IPv6 address in network byte order.
    + * @port: TCP or UDP's port number.
    + *
    + * Returns zero if permission granted.
    + * Returns nonzero if permission denied.
    + */
    +int tmy_network_listen_acl(const u8 is_ipv6,
    + const u8 *address,
    + const u16 port)
    +{
    + return tmy_network_entry(is_ipv6,
    + TMY_NETWORK_ACL_TCP_LISTEN,
    + (const u32 *) address,
    + ntohs(port));
    +}
    +
    +/**
    + * tmy_network_connect_acl - check permission for connect(2) operation.
    + * @is_ipv6: is @address an IPv6 address?
    + * @sock_type: socket type (TCP, UDP or IP).
    + * @address: pointer to IPv4/IPv6 address in network byte order.
    + * @port: TCP or UDP's port number or IP's protocol number.
    + *
    + * Returns zero if permission granted.
    + * Returns nonzero if permission denied.
    + */
    +int tmy_network_connect_acl(const u8 is_ipv6,
    + const int sock_type,
    + const u8 *address,
    + const u16 port)
    +{
    + int type;
    +
    + switch (sock_type) {
    + case SOCK_STREAM:
    + type = TMY_NETWORK_ACL_TCP_CONNECT;
    + break;
    + case SOCK_DGRAM:
    + type = TMY_NETWORK_ACL_UDP_CONNECT;
    + break;
    + default:
    + type = TMY_NETWORK_ACL_RAW_CONNECT;
    + break;
    + }
    +
    + return tmy_network_entry(is_ipv6, type,
    + (const u32 *) address, ntohs(port));
    +}
    +
    +/**
    + * tmy_network_bind_acl - check permission for bind(2) operation.
    + * @is_ipv6: is @address an IPv6 address?
    + * @sock_type: socket type (TCP, UDP or IP).
    + * @address: pointer to IPv4/IPv6 address in network byte order.
    + * @port: TCP or UDP's port number or IP's protocol number.
    + *
    + * Returns zero if permission granted.
    + * Returns nonzero if permission denied.
    + */
    +int tmy_network_bind_acl(const u8 is_ipv6,
    + const int sock_type,
    + const u8 *address,
    + const u16 port)
    +{
    + int type;
    +
    + switch (sock_type) {
    + case SOCK_STREAM:
    + type = TMY_NETWORK_ACL_TCP_BIND;
    + break;
    + case SOCK_DGRAM:
    + type = TMY_NETWORK_ACL_UDP_BIND;
    + break;
    + default:
    + type = TMY_NETWORK_ACL_RAW_BIND;
    + break;
    + }
    +
    + return tmy_network_entry(is_ipv6, type,
    + (const u32 *) address, ntohs(port));
    +}
    +
    +/**
    + * tmy_network_sendmsg_acl - check permission for sendmsg(2) operation.
    + * @is_ipv6: is @address an IPv6 address?
    + * @sock_type: socket type (UDP or IP).
    + * @address: pointer to IPv4/IPv6 address in network byte order.
    + * @port: UDP's port number or IP's protocol number.
    + *
    + * Returns zero if permission granted.
    + * Returns nonzero if permission denied.
    + */
    +int tmy_network_sendmsg_acl(const u8 is_ipv6,
    + const int sock_type,
    + const u8 *address,
    + const u16 port)
    +{
    + int type;
    +
    + if (sock_type == SOCK_DGRAM)
    + type = SOCK_DGRAM;
    + else
    + type = TMY_NETWORK_ACL_RAW_CONNECT;
    +
    + return tmy_network_entry(is_ipv6, type,
    + (const u32 *) address, ntohs(port));
    +}
    +
    +/**
    + * tmy_network_accept_acl - check permission for accept(2) operation.
    + * @is_ipv6: is @address an IPv6 address?
    + * @address: pointer to IPv4/IPv6 address in network byte order.
    + * @port: TCP client's port number.
    + *
    + * Returns zero if permission granted.
    + * Returns nonzero if permission denied.
    + */
    +int tmy_network_accept_acl(const u8 is_ipv6, const u8 *address,
    + const u16 port)
    +{
    + return tmy_network_entry(is_ipv6, TMY_NETWORK_ACL_TCP_ACCEPT,
    + (const u32 *) address, ntohs(port));
    +}
    +
    +/**
    + * tmy_network_recvmsg_acl - check permission for recvmsg(2) operation.
    + * @is_ipv6: is @address an IPv6 address?
    + * @sock_type: socket type (UDP or IP).
    + * @address: pointer to IPv4/IPv6 address in network byte order.
    + * @port: UDP's port number or IP's protocol number.
    + *
    + * Returns zero if permission granted.
    + * Returns nonzero if permission denied.
    + */
    +int tmy_network_recvmsg_acl(const u8 is_ipv6, const int sock_type,
    + const u8 *address, const u16 port)
    +{
    + return tmy_network_entry(is_ipv6, sock_type == SOCK_DGRAM ?
    + TMY_NETWORK_ACL_UDP_CONNECT :
    + TMY_NETWORK_ACL_RAW_CONNECT,
    + (const u32 *) address, ntohs(port));
    +}

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-10-02 09:39    [W:5.173 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site