3 |
* |
* |
4 |
* Copyright (C) 2005-2010 NTT DATA CORPORATION |
* Copyright (C) 2005-2010 NTT DATA CORPORATION |
5 |
* |
* |
6 |
* Version: 1.7.2-pre 2010/03/08 |
* Version: 1.7.2 2010/04/01 |
7 |
* |
* |
8 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
9 |
* See README.ccs for ChangeLog. |
* See README.ccs for ChangeLog. |
36 |
{ |
{ |
37 |
if (!is_granted) |
if (!is_granted) |
38 |
ccs_warn_log(r, "%s %s %u", operation, address, port); |
ccs_warn_log(r, "%s %s %u", operation, address, port); |
39 |
return ccs_write_audit_log(is_granted, r, CCS_KEYWORD_ALLOW_NETWORK |
return ccs_write_log(is_granted, r, CCS_KEYWORD_ALLOW_NETWORK |
40 |
"%s %s %u\n", operation, address, port); |
"%s %s %u\n", operation, address, port); |
41 |
} |
} |
42 |
|
|
47 |
* @min: Pointer to store min address. |
* @min: Pointer to store min address. |
48 |
* @max: Pointer to store max address. |
* @max: Pointer to store max address. |
49 |
* |
* |
50 |
* Returns 2 if @address is an IPv6, 1 if @address is an IPv4, 0 otherwise. |
* Returns CCS_IP_ADDRESS_TYPE_IPv6 if @address is an IPv6, |
51 |
|
* CCS_IP_ADDRESS_TYPE_IPv4 if @address is an IPv4, |
52 |
|
* CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP otherwise. |
53 |
*/ |
*/ |
54 |
int ccs_parse_ip_address(char *address, u16 *min, u16 *max) |
int ccs_parse_ip_address(char *address, u16 *min, u16 *max) |
55 |
{ |
{ |
67 |
min[i] = htons(min[i]); |
min[i] = htons(min[i]); |
68 |
max[i] = htons(max[i]); |
max[i] = htons(max[i]); |
69 |
} |
} |
70 |
return 2; |
return CCS_IP_ADDRESS_TYPE_IPv6; |
71 |
} |
} |
72 |
count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu", |
count = sscanf(address, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu", |
73 |
&min[0], &min[1], &min[2], &min[3], |
&min[0], &min[1], &min[2], &min[3], |
77 |
+ (((u8) min[2]) << 8) + (u8) min[3]); |
+ (((u8) min[2]) << 8) + (u8) min[3]); |
78 |
memmove(min, &ip, sizeof(ip)); |
memmove(min, &ip, sizeof(ip)); |
79 |
if (count == 8) |
if (count == 8) |
80 |
ip = htonl((((u8) max[0]) << 24) + (((u8) max[1]) << 16) |
ip = htonl((((u8) max[0]) << 24) |
81 |
|
+ (((u8) max[1]) << 16) |
82 |
+ (((u8) max[2]) << 8) + (u8) max[3]); |
+ (((u8) max[2]) << 8) + (u8) max[3]); |
83 |
memmove(max, &ip, sizeof(ip)); |
memmove(max, &ip, sizeof(ip)); |
84 |
return 1; |
return CCS_IP_ADDRESS_TYPE_IPv4; |
85 |
} |
} |
86 |
return 0; |
return CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP; |
87 |
|
} |
88 |
|
|
89 |
|
/** |
90 |
|
* ccs_print_ipv4 - Print an IPv4 address. |
91 |
|
* |
92 |
|
* @buffer: Buffer to write to. |
93 |
|
* @buffer_len: Size of @buffer. |
94 |
|
* @min_ip: Min address in host byte order. |
95 |
|
* @max_ip: Max address in host byte order. |
96 |
|
* |
97 |
|
* Returns nothing. |
98 |
|
*/ |
99 |
|
void ccs_print_ipv4(char *buffer, const int buffer_len, |
100 |
|
const u32 min_ip, const u32 max_ip) |
101 |
|
{ |
102 |
|
memset(buffer, 0, buffer_len); |
103 |
|
snprintf(buffer, buffer_len - 1, "%u.%u.%u.%u%c%u.%u.%u.%u", |
104 |
|
HIPQUAD(min_ip), min_ip == max_ip ? '\0' : '-', |
105 |
|
HIPQUAD(max_ip)); |
106 |
} |
} |
107 |
|
|
108 |
#if !defined(NIP6) |
#if !defined(NIP6) |
118 |
* |
* |
119 |
* @buffer: Buffer to write to. |
* @buffer: Buffer to write to. |
120 |
* @buffer_len: Size of @buffer. |
* @buffer_len: Size of @buffer. |
121 |
* @ip: Pointer to "struct in6_addr". |
* @min_ip: Pointer to "struct in6_addr". |
122 |
|
* @max_ip: Pointer to "struct in6_addr". |
123 |
* |
* |
124 |
* Returns nothing. |
* Returns nothing. |
125 |
*/ |
*/ |
126 |
void ccs_print_ipv6(char *buffer, const int buffer_len, |
void ccs_print_ipv6(char *buffer, const int buffer_len, |
127 |
const struct in6_addr *ip) |
const struct in6_addr *min_ip, |
128 |
|
const struct in6_addr *max_ip) |
129 |
{ |
{ |
130 |
memset(buffer, 0, buffer_len); |
memset(buffer, 0, buffer_len); |
131 |
snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip)); |
snprintf(buffer, buffer_len - 1, |
132 |
|
"%x:%x:%x:%x:%x:%x:%x:%x%c%x:%x:%x:%x:%x:%x:%x:%x", |
133 |
|
NIP6(*min_ip), min_ip == max_ip ? '\0' : '-', |
134 |
|
NIP6(*max_ip)); |
135 |
} |
} |
136 |
|
|
137 |
/** |
/** |
195 |
/* using host byte order to allow u32 comparison than memcmp().*/ |
/* using host byte order to allow u32 comparison than memcmp().*/ |
196 |
const u32 ip = ntohl(*address); |
const u32 ip = ntohl(*address); |
197 |
int error; |
int error; |
198 |
char buf[64]; |
char buf[128]; |
199 |
if (ccs_init_request_info(&r, NULL, |
const struct ccs_domain_info * const domain = ccs_current_domain(); |
200 |
CCS_MAC_NETWORK_UDP_BIND + operation) |
if (ccs_init_request_info(&r, CCS_MAC_NETWORK_UDP_BIND + operation) |
201 |
== CCS_CONFIG_DISABLED) |
== CCS_CONFIG_DISABLED) |
202 |
return 0; |
return 0; |
|
memset(buf, 0, sizeof(buf)); |
|
203 |
if (is_ipv6) |
if (is_ipv6) |
204 |
ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) |
ccs_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) |
205 |
address); |
address, (const struct in6_addr *) address); |
206 |
else |
else |
207 |
snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip)); |
ccs_print_ipv4(buf, sizeof(buf), ip, ip); |
208 |
do { |
do { |
209 |
error = -EPERM; |
error = -EPERM; |
210 |
list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) { |
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
211 |
struct ccs_ip_network_acl *acl; |
struct ccs_ip_network_acl *acl; |
212 |
if (ptr->is_deleted || |
if (ptr->is_deleted || |
213 |
ptr->type != CCS_TYPE_IP_NETWORK_ACL) |
ptr->type != CCS_TYPE_IP_NETWORK_ACL) |
276 |
return error; |
return error; |
277 |
} |
} |
278 |
|
|
279 |
|
static bool ccs_same_ip_network_acl(const struct ccs_acl_info *a, |
280 |
|
const struct ccs_acl_info *b) |
281 |
|
{ |
282 |
|
const struct ccs_ip_network_acl *p1 = container_of(a, typeof(*p1), |
283 |
|
head); |
284 |
|
const struct ccs_ip_network_acl *p2 = container_of(b, typeof(*p2), |
285 |
|
head); |
286 |
|
return ccs_same_acl_head(&p1->head, &p2->head) |
287 |
|
&& p1->address_type == p2->address_type && |
288 |
|
p1->address.ipv4.min == p2->address.ipv4.min && |
289 |
|
p1->address.ipv6.min == p2->address.ipv6.min && |
290 |
|
p1->address.ipv4.max == p2->address.ipv4.max && |
291 |
|
p1->address.ipv6.max == p2->address.ipv6.max && |
292 |
|
p1->address.group == p2->address.group && |
293 |
|
ccs_same_number_union(&p1->port, &p2->port); |
294 |
|
} |
295 |
|
|
296 |
|
static bool ccs_merge_ip_network_acl(struct ccs_acl_info *a, |
297 |
|
struct ccs_acl_info *b, |
298 |
|
const bool is_delete) |
299 |
|
{ |
300 |
|
u8 * const a_perm = &container_of(a, struct ccs_ip_network_acl, head) |
301 |
|
->perm; |
302 |
|
u8 perm = *a_perm; |
303 |
|
const u8 b_perm = container_of(b, struct ccs_ip_network_acl, head) |
304 |
|
->perm; |
305 |
|
if (is_delete) |
306 |
|
perm &= ~b_perm; |
307 |
|
else |
308 |
|
perm |= b_perm; |
309 |
|
*a_perm = perm; |
310 |
|
return !perm; |
311 |
|
} |
312 |
|
|
313 |
/** |
/** |
314 |
* ccs_write_network_policy - Write "struct ccs_ip_network_acl" list. |
* ccs_write_network - Write "struct ccs_ip_network_acl" list. |
315 |
* |
* |
316 |
* @data: String to parse. |
* @data: String to parse. |
317 |
* @domain: Pointer to "struct ccs_domain_info". |
* @domain: Pointer to "struct ccs_domain_info". |
320 |
* |
* |
321 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
322 |
*/ |
*/ |
323 |
int ccs_write_network_policy(char *data, struct ccs_domain_info *domain, |
int ccs_write_network(char *data, struct ccs_domain_info *domain, |
324 |
struct ccs_condition *condition, |
struct ccs_condition *condition, const bool is_delete) |
|
const bool is_delete) |
|
325 |
{ |
{ |
|
struct ccs_ip_network_acl *entry = NULL; |
|
|
struct ccs_acl_info *ptr; |
|
326 |
struct ccs_ip_network_acl e = { |
struct ccs_ip_network_acl e = { |
327 |
.head.type = CCS_TYPE_IP_NETWORK_ACL, |
.head.type = CCS_TYPE_IP_NETWORK_ACL, |
328 |
.head.cond = condition, |
.head.cond = condition, |
373 |
else |
else |
374 |
return -EINVAL; |
return -EINVAL; |
375 |
switch (ccs_parse_ip_address(w[2], min_address, max_address)) { |
switch (ccs_parse_ip_address(w[2], min_address, max_address)) { |
376 |
case 2: |
case CCS_IP_ADDRESS_TYPE_IPv6: |
377 |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv6; |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv6; |
378 |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
379 |
min_address); |
min_address); |
382 |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
383 |
goto out; |
goto out; |
384 |
break; |
break; |
385 |
case 1: |
case CCS_IP_ADDRESS_TYPE_IPv4: |
386 |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv4; |
e.address_type = CCS_IP_ADDRESS_TYPE_IPv4; |
387 |
/* use host byte order to allow u32 comparison.*/ |
/* use host byte order to allow u32 comparison.*/ |
388 |
e.address.ipv4.min = ntohl(*(u32 *) min_address); |
e.address.ipv4.min = ntohl(*(u32 *) min_address); |
392 |
if (w[2][0] != '@') |
if (w[2][0] != '@') |
393 |
return -EINVAL; |
return -EINVAL; |
394 |
e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP; |
e.address_type = CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP; |
395 |
e.address.group = ccs_get_address_group(w[2] + 1); |
e.address.group = ccs_get_group(w[2] + 1, CCS_ADDRESS_GROUP); |
396 |
if (!e.address.group) |
if (!e.address.group) |
397 |
return -ENOMEM; |
return -ENOMEM; |
398 |
break; |
break; |
399 |
} |
} |
400 |
if (!ccs_parse_number_union(w[3], &e.port)) |
if (!ccs_parse_number_union(w[3], &e.port)) |
401 |
goto out; |
goto out; |
402 |
if (!is_delete) |
error = ccs_update_domain(&e.head, sizeof(e), is_delete, domain, |
403 |
entry = kmalloc(sizeof(e), GFP_KERNEL); |
ccs_same_ip_network_acl, |
404 |
mutex_lock(&ccs_policy_lock); |
ccs_merge_ip_network_acl); |
|
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
|
|
struct ccs_ip_network_acl *acl = |
|
|
container_of(ptr, struct ccs_ip_network_acl, head); |
|
|
if (ptr->type != CCS_TYPE_IP_NETWORK_ACL || |
|
|
ptr->cond != condition || |
|
|
ccs_memcmp(acl, &e, offsetof(typeof(e), address_type), |
|
|
sizeof(e))) |
|
|
continue; |
|
|
if (is_delete) { |
|
|
acl->perm &= ~e.perm; |
|
|
if (!acl->perm) |
|
|
ptr->is_deleted = true; |
|
|
} else { |
|
|
if (ptr->is_deleted) |
|
|
acl->perm = 0; |
|
|
acl->perm |= e.perm; |
|
|
ptr->is_deleted = false; |
|
|
} |
|
|
error = 0; |
|
|
break; |
|
|
} |
|
|
if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) { |
|
|
ccs_add_domain_acl(domain, &entry->head); |
|
|
entry = NULL; |
|
|
error = 0; |
|
|
} |
|
|
mutex_unlock(&ccs_policy_lock); |
|
405 |
out: |
out: |
406 |
if (w[2][0] == '@') |
if (w[2][0] == '@') |
407 |
ccs_put_address_group(e.address.group); |
ccs_put_group(e.address.group); |
408 |
else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) { |
else if (e.address_type == CCS_IP_ADDRESS_TYPE_IPv6) { |
409 |
ccs_put_ipv6_address(e.address.ipv6.min); |
ccs_put_ipv6_address(e.address.ipv6.min); |
410 |
ccs_put_ipv6_address(e.address.ipv6.max); |
ccs_put_ipv6_address(e.address.ipv6.max); |
411 |
} |
} |
412 |
ccs_put_number_union(&e.port); |
ccs_put_number_union(&e.port); |
|
kfree(entry); |
|
413 |
return error; |
return error; |
414 |
} |
} |
415 |
|
|
422 |
* |
* |
423 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
424 |
*/ |
*/ |
425 |
static inline int ccs_network_listen_acl(const bool is_ipv6, const u8 *address, |
static int ccs_network_listen_acl(const bool is_ipv6, const u8 *address, |
426 |
const u16 port) |
const u16 port) |
427 |
{ |
{ |
428 |
return ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN, |
return ccs_network_entry(is_ipv6, CCS_NETWORK_TCP_LISTEN, |
429 |
(const u32 *) address, ntohs(port)); |
(const u32 *) address, ntohs(port)); |
439 |
* |
* |
440 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
441 |
*/ |
*/ |
442 |
static inline int ccs_network_connect_acl(const bool is_ipv6, |
static int ccs_network_connect_acl(const bool is_ipv6, const int sock_type, |
443 |
const int sock_type, |
const u8 *address, const u16 port) |
|
const u8 *address, const u16 port) |
|
444 |
{ |
{ |
445 |
u8 operation; |
u8 operation; |
446 |
switch (sock_type) { |
switch (sock_type) { |
494 |
* |
* |
495 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
496 |
*/ |
*/ |
497 |
static inline int ccs_network_accept_acl(const bool is_ipv6, const u8 *address, |
static int ccs_network_accept_acl(const bool is_ipv6, const u8 *address, |
498 |
const u16 port) |
const u16 port) |
499 |
{ |
{ |
500 |
int retval; |
int retval; |
501 |
current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
current->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
515 |
* |
* |
516 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
517 |
*/ |
*/ |
518 |
static inline int ccs_network_sendmsg_acl(const bool is_ipv6, |
static int ccs_network_sendmsg_acl(const bool is_ipv6, const int sock_type, |
519 |
const int sock_type, |
const u8 *address, const u16 port) |
|
const u8 *address, const u16 port) |
|
520 |
{ |
{ |
521 |
u8 operation; |
u8 operation; |
522 |
if (sock_type == SOCK_DGRAM) |
if (sock_type == SOCK_DGRAM) |
537 |
* |
* |
538 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
539 |
*/ |
*/ |
540 |
static inline int ccs_network_recvmsg_acl(const bool is_ipv6, |
static int ccs_network_recvmsg_acl(const bool is_ipv6, const int sock_type, |
541 |
const int sock_type, |
const u8 *address, const u16 port) |
|
const u8 *address, const u16 port) |
|
542 |
{ |
{ |
543 |
int retval; |
int retval; |
544 |
const u8 operation |
const u8 operation |
551 |
return retval; |
return retval; |
552 |
} |
} |
553 |
|
|
554 |
|
#ifndef CONFIG_NET |
555 |
|
|
556 |
|
void __init ccs_network_init(void) |
557 |
|
{ |
558 |
|
} |
559 |
|
|
560 |
|
#else |
561 |
|
|
562 |
#define MAX_SOCK_ADDR 128 /* net/socket.c */ |
#define MAX_SOCK_ADDR 128 /* net/socket.c */ |
563 |
|
|
564 |
/* Check permission for creating a socket. */ |
/* Check permission for creating a socket. */ |
972 |
ccsecurity_ops.socket_recvmsg_permission = |
ccsecurity_ops.socket_recvmsg_permission = |
973 |
__ccs_socket_recvmsg_permission; |
__ccs_socket_recvmsg_permission; |
974 |
} |
} |
975 |
|
|
976 |
|
#endif |