#include <stdlib.h>
|
#include <string.h>
|
#include <netinet/in.h>
|
#include <arpa/inet.h>
|
#include <errno.h>
|
#include <sepol/ibpkey_record.h>
|
|
#include "ibpkey_internal.h"
|
#include "context_internal.h"
|
#include "debug.h"
|
|
struct sepol_ibpkey {
|
/* Subnet prefix */
|
uint64_t subnet_prefix;
|
|
/* Low - High range. Same for single ibpkeys. */
|
int low, high;
|
|
/* Context */
|
sepol_context_t *con;
|
};
|
|
struct sepol_ibpkey_key {
|
/* Subnet prefix */
|
uint64_t subnet_prefix;
|
|
/* Low - High range. Same for single ibpkeys. */
|
int low, high;
|
};
|
|
/* Converts a string represtation (subnet_prefix_str)
|
* to a numeric representation (subnet_prefix_bytes)
|
*/
|
static int ibpkey_parse_subnet_prefix(sepol_handle_t *handle,
|
const char *subnet_prefix_str,
|
uint64_t *subnet_prefix)
|
{
|
struct in6_addr in_addr;
|
|
if (inet_pton(AF_INET6, subnet_prefix_str, &in_addr) <= 0) {
|
ERR(handle, "could not parse IPv6 address for ibpkey subnet prefix %s: %s",
|
subnet_prefix_str, strerror(errno));
|
return STATUS_ERR;
|
}
|
|
memcpy(subnet_prefix, in_addr.s6_addr, sizeof(*subnet_prefix));
|
|
return STATUS_SUCCESS;
|
}
|
|
/* Converts a numeric representation (subnet_prefix_bytes)
|
* to a string representation (subnet_prefix_str)
|
*/
|
|
static int ibpkey_expand_subnet_prefix(sepol_handle_t *handle,
|
uint64_t subnet_prefix,
|
char *subnet_prefix_str)
|
{
|
struct in6_addr addr;
|
|
memset(&addr, 0, sizeof(struct in6_addr));
|
memcpy(&addr.s6_addr[0], &subnet_prefix, sizeof(subnet_prefix));
|
|
if (inet_ntop(AF_INET6, &addr, subnet_prefix_str,
|
INET6_ADDRSTRLEN) == NULL) {
|
ERR(handle,
|
"could not expand IPv6 address to string: %s",
|
strerror(errno));
|
return STATUS_ERR;
|
}
|
|
return STATUS_SUCCESS;
|
}
|
|
/* Allocates a sufficiently large string (subnet_prefix)
|
* for an IPV6 address for the subnet prefix
|
*/
|
static int ibpkey_alloc_subnet_prefix_string(sepol_handle_t *handle,
|
char **subnet_prefix)
|
{
|
char *tmp_subnet_prefix = NULL;
|
|
tmp_subnet_prefix = malloc(INET6_ADDRSTRLEN);
|
|
if (!tmp_subnet_prefix)
|
goto omem;
|
|
*subnet_prefix = tmp_subnet_prefix;
|
return STATUS_SUCCESS;
|
|
omem:
|
ERR(handle, "out of memory");
|
|
ERR(handle, "could not allocate string buffer for subnet_prefix");
|
return STATUS_ERR;
|
}
|
|
/* Key */
|
int sepol_ibpkey_key_create(sepol_handle_t *handle,
|
const char *subnet_prefix,
|
int low, int high,
|
sepol_ibpkey_key_t **key_ptr)
|
{
|
sepol_ibpkey_key_t *tmp_key =
|
(sepol_ibpkey_key_t *)malloc(sizeof(sepol_ibpkey_key_t));
|
|
if (!tmp_key) {
|
ERR(handle, "out of memory, could not create ibpkey key");
|
goto omem;
|
}
|
|
if (ibpkey_parse_subnet_prefix(handle, subnet_prefix, &tmp_key->subnet_prefix) < 0)
|
goto err;
|
|
tmp_key->low = low;
|
tmp_key->high = high;
|
|
*key_ptr = tmp_key;
|
return STATUS_SUCCESS;
|
|
omem:
|
ERR(handle, "out of memory");
|
|
err:
|
sepol_ibpkey_key_free(tmp_key);
|
ERR(handle, "could not create ibpkey key for subnet prefix%s, range %u, %u",
|
subnet_prefix, low, high);
|
return STATUS_ERR;
|
}
|
|
hidden_def(sepol_ibpkey_key_create)
|
|
void sepol_ibpkey_key_unpack(const sepol_ibpkey_key_t *key,
|
uint64_t *subnet_prefix, int *low, int *high)
|
{
|
*subnet_prefix = key->subnet_prefix;
|
*low = key->low;
|
*high = key->high;
|
}
|
|
hidden_def(sepol_ibpkey_key_unpack)
|
|
int sepol_ibpkey_key_extract(sepol_handle_t *handle,
|
const sepol_ibpkey_t *ibpkey,
|
sepol_ibpkey_key_t **key_ptr)
|
{
|
char subnet_prefix_str[INET6_ADDRSTRLEN];
|
|
ibpkey_expand_subnet_prefix(handle, ibpkey->subnet_prefix, subnet_prefix_str);
|
|
if (sepol_ibpkey_key_create
|
(handle, subnet_prefix_str, ibpkey->low, ibpkey->high, key_ptr) < 0) {
|
ERR(handle, "could not extract key from ibpkey %s %d:%d",
|
subnet_prefix_str,
|
ibpkey->low, ibpkey->high);
|
|
return STATUS_ERR;
|
}
|
|
return STATUS_SUCCESS;
|
}
|
|
void sepol_ibpkey_key_free(sepol_ibpkey_key_t *key)
|
{
|
if (!key)
|
return;
|
free(key);
|
}
|
|
int sepol_ibpkey_compare(const sepol_ibpkey_t *ibpkey, const sepol_ibpkey_key_t *key)
|
{
|
if (ibpkey->subnet_prefix < key->subnet_prefix)
|
return -1;
|
if (key->subnet_prefix < ibpkey->subnet_prefix)
|
return 1;
|
|
if (ibpkey->low < key->low)
|
return -1;
|
if (key->low < ibpkey->low)
|
return 1;
|
|
if (ibpkey->high < key->high)
|
return -1;
|
if (key->high < ibpkey->high)
|
return 1;
|
|
return 0;
|
}
|
|
int sepol_ibpkey_compare2(const sepol_ibpkey_t *ibpkey, const sepol_ibpkey_t *ibpkey2)
|
{
|
if (ibpkey->subnet_prefix < ibpkey2->subnet_prefix)
|
return -1;
|
if (ibpkey2->subnet_prefix < ibpkey->subnet_prefix)
|
return 1;
|
|
if (ibpkey->low < ibpkey2->low)
|
return -1;
|
if (ibpkey2->low < ibpkey->low)
|
return 1;
|
|
if (ibpkey->high < ibpkey2->high)
|
return -1;
|
if (ibpkey2->high < ibpkey->high)
|
return 1;
|
|
return 0;
|
}
|
|
/* Pkey */
|
int sepol_ibpkey_get_low(const sepol_ibpkey_t *ibpkey)
|
{
|
return ibpkey->low;
|
}
|
|
hidden_def(sepol_ibpkey_get_low)
|
|
int sepol_ibpkey_get_high(const sepol_ibpkey_t *ibpkey)
|
{
|
return ibpkey->high;
|
}
|
|
hidden_def(sepol_ibpkey_get_high)
|
|
void sepol_ibpkey_set_pkey(sepol_ibpkey_t *ibpkey, int pkey_num)
|
{
|
ibpkey->low = pkey_num;
|
ibpkey->high = pkey_num;
|
}
|
|
void sepol_ibpkey_set_range(sepol_ibpkey_t *ibpkey, int low, int high)
|
{
|
ibpkey->low = low;
|
ibpkey->high = high;
|
}
|
|
hidden_def(sepol_ibpkey_set_range)
|
|
int sepol_ibpkey_get_subnet_prefix(sepol_handle_t *handle,
|
const sepol_ibpkey_t *ibpkey,
|
char **subnet_prefix)
|
{
|
char *tmp_subnet_prefix = NULL;
|
|
if (ibpkey_alloc_subnet_prefix_string(handle, &tmp_subnet_prefix) < 0)
|
goto err;
|
|
if (ibpkey_expand_subnet_prefix(handle, ibpkey->subnet_prefix, tmp_subnet_prefix) < 0)
|
goto err;
|
|
*subnet_prefix = tmp_subnet_prefix;
|
return STATUS_SUCCESS;
|
|
err:
|
free(tmp_subnet_prefix);
|
ERR(handle, "could not get ibpkey subnet_prefix");
|
return STATUS_ERR;
|
}
|
|
hidden_def(sepol_ibpkey_get_subnet_prefix)
|
|
/* Subnet prefix */
|
uint64_t sepol_ibpkey_get_subnet_prefix_bytes(const sepol_ibpkey_t *ibpkey)
|
{
|
return ibpkey->subnet_prefix;
|
}
|
|
hidden_def(sepol_ibpkey_get_subnet_prefix_bytes)
|
|
int sepol_ibpkey_set_subnet_prefix(sepol_handle_t *handle,
|
sepol_ibpkey_t *ibpkey,
|
const char *subnet_prefix_str)
|
{
|
uint64_t tmp = 0;
|
|
if (ibpkey_parse_subnet_prefix(handle, subnet_prefix_str, &tmp) < 0)
|
goto err;
|
|
ibpkey->subnet_prefix = tmp;
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not set ibpkey subnet prefix to %s", subnet_prefix_str);
|
return STATUS_ERR;
|
}
|
|
hidden_def(sepol_ibpkey_set_subnet_prefix)
|
|
void sepol_ibpkey_set_subnet_prefix_bytes(sepol_ibpkey_t *ibpkey,
|
uint64_t subnet_prefix)
|
{
|
ibpkey->subnet_prefix = subnet_prefix;
|
}
|
|
hidden_def(sepol_ibpkey_set_subnet_prefix_bytes)
|
|
/* Create */
|
int sepol_ibpkey_create(sepol_handle_t *handle, sepol_ibpkey_t **ibpkey)
|
{
|
sepol_ibpkey_t *tmp_ibpkey = (sepol_ibpkey_t *)malloc(sizeof(sepol_ibpkey_t));
|
|
if (!tmp_ibpkey) {
|
ERR(handle, "out of memory, could not create ibpkey record");
|
return STATUS_ERR;
|
}
|
|
tmp_ibpkey->subnet_prefix = 0;
|
tmp_ibpkey->low = 0;
|
tmp_ibpkey->high = 0;
|
tmp_ibpkey->con = NULL;
|
*ibpkey = tmp_ibpkey;
|
|
return STATUS_SUCCESS;
|
}
|
|
hidden_def(sepol_ibpkey_create)
|
|
/* Deep copy clone */
|
int sepol_ibpkey_clone(sepol_handle_t *handle,
|
const sepol_ibpkey_t *ibpkey, sepol_ibpkey_t **ibpkey_ptr)
|
{
|
sepol_ibpkey_t *new_ibpkey = NULL;
|
|
if (sepol_ibpkey_create(handle, &new_ibpkey) < 0)
|
goto err;
|
|
new_ibpkey->subnet_prefix = ibpkey->subnet_prefix;
|
new_ibpkey->low = ibpkey->low;
|
new_ibpkey->high = ibpkey->high;
|
|
if (ibpkey->con &&
|
(sepol_context_clone(handle, ibpkey->con, &new_ibpkey->con) < 0))
|
goto err;
|
|
*ibpkey_ptr = new_ibpkey;
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not clone ibpkey record");
|
sepol_ibpkey_free(new_ibpkey);
|
return STATUS_ERR;
|
}
|
|
/* Destroy */
|
void sepol_ibpkey_free(sepol_ibpkey_t *ibpkey)
|
{
|
if (!ibpkey)
|
return;
|
|
sepol_context_free(ibpkey->con);
|
free(ibpkey);
|
}
|
|
hidden_def(sepol_ibpkey_free)
|
|
/* Context */
|
sepol_context_t *sepol_ibpkey_get_con(const sepol_ibpkey_t *ibpkey)
|
{
|
return ibpkey->con;
|
}
|
|
hidden_def(sepol_ibpkey_get_con)
|
|
int sepol_ibpkey_set_con(sepol_handle_t *handle,
|
sepol_ibpkey_t *ibpkey, sepol_context_t *con)
|
{
|
sepol_context_t *newcon;
|
|
if (sepol_context_clone(handle, con, &newcon) < 0) {
|
ERR(handle, "out of memory, could not set ibpkey context");
|
return STATUS_ERR;
|
}
|
|
sepol_context_free(ibpkey->con);
|
ibpkey->con = newcon;
|
return STATUS_SUCCESS;
|
}
|
|
hidden_def(sepol_ibpkey_set_con)
|