#include <netinet/in.h>
|
#ifndef IPPROTO_DCCP
|
#define IPPROTO_DCCP 33
|
#endif
|
#ifndef IPPROTO_SCTP
|
#define IPPROTO_SCTP 132
|
#endif
|
#include <stdlib.h>
|
|
#include "debug.h"
|
#include "context.h"
|
#include "handle.h"
|
|
#include <sepol/policydb/policydb.h>
|
#include "port_internal.h"
|
|
static inline int sepol2ipproto(sepol_handle_t * handle, int proto)
|
{
|
|
switch (proto) {
|
case SEPOL_PROTO_TCP:
|
return IPPROTO_TCP;
|
case SEPOL_PROTO_UDP:
|
return IPPROTO_UDP;
|
case SEPOL_PROTO_DCCP:
|
return IPPROTO_DCCP;
|
case SEPOL_PROTO_SCTP:
|
return IPPROTO_SCTP;
|
default:
|
ERR(handle, "unsupported protocol %u", proto);
|
return STATUS_ERR;
|
}
|
}
|
|
static inline int ipproto2sepol(sepol_handle_t * handle, int proto)
|
{
|
|
switch (proto) {
|
case IPPROTO_TCP:
|
return SEPOL_PROTO_TCP;
|
case IPPROTO_UDP:
|
return SEPOL_PROTO_UDP;
|
case IPPROTO_DCCP:
|
return SEPOL_PROTO_DCCP;
|
case IPPROTO_SCTP:
|
return SEPOL_PROTO_SCTP;
|
default:
|
ERR(handle, "invalid protocol %u " "found in policy", proto);
|
return STATUS_ERR;
|
}
|
}
|
|
/* Create a low level port structure from
|
* a high level representation */
|
static int port_from_record(sepol_handle_t * handle,
|
const policydb_t * policydb,
|
ocontext_t ** port, const sepol_port_t * data)
|
{
|
|
ocontext_t *tmp_port = NULL;
|
context_struct_t *tmp_con = NULL;
|
int tmp_proto;
|
|
int low = sepol_port_get_low(data);
|
int high = sepol_port_get_high(data);
|
int proto = sepol_port_get_proto(data);
|
|
tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t));
|
if (!tmp_port)
|
goto omem;
|
|
/* Process protocol */
|
tmp_proto = sepol2ipproto(handle, proto);
|
if (tmp_proto < 0)
|
goto err;
|
tmp_port->u.port.protocol = tmp_proto;
|
|
/* Port range */
|
tmp_port->u.port.low_port = low;
|
tmp_port->u.port.high_port = high;
|
if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) {
|
ERR(handle, "low port %d exceeds high port %d",
|
tmp_port->u.port.low_port, tmp_port->u.port.high_port);
|
goto err;
|
}
|
|
/* Context */
|
if (context_from_record(handle, policydb, &tmp_con,
|
sepol_port_get_con(data)) < 0)
|
goto err;
|
context_cpy(&tmp_port->context[0], tmp_con);
|
context_destroy(tmp_con);
|
free(tmp_con);
|
tmp_con = NULL;
|
|
*port = tmp_port;
|
return STATUS_SUCCESS;
|
|
omem:
|
ERR(handle, "out of memory");
|
|
err:
|
if (tmp_port != NULL) {
|
context_destroy(&tmp_port->context[0]);
|
free(tmp_port);
|
}
|
context_destroy(tmp_con);
|
free(tmp_con);
|
ERR(handle, "could not create port structure for range %u:%u (%s)",
|
low, high, sepol_port_get_proto_str(proto));
|
return STATUS_ERR;
|
}
|
|
static int port_to_record(sepol_handle_t * handle,
|
const policydb_t * policydb,
|
ocontext_t * port, sepol_port_t ** record)
|
{
|
|
int proto = port->u.port.protocol;
|
int low = port->u.port.low_port;
|
int high = port->u.port.high_port;
|
context_struct_t *con = &port->context[0];
|
int rec_proto = -1;
|
|
sepol_context_t *tmp_con = NULL;
|
sepol_port_t *tmp_record = NULL;
|
|
if (sepol_port_create(handle, &tmp_record) < 0)
|
goto err;
|
|
rec_proto = ipproto2sepol(handle, proto);
|
if (rec_proto < 0)
|
goto err;
|
|
sepol_port_set_proto(tmp_record, rec_proto);
|
sepol_port_set_range(tmp_record, low, high);
|
|
if (context_to_record(handle, policydb, con, &tmp_con) < 0)
|
goto err;
|
|
if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0)
|
goto err;
|
|
sepol_context_free(tmp_con);
|
*record = tmp_record;
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not convert port range %u - %u (%s) "
|
"to record", low, high, sepol_port_get_proto_str(rec_proto));
|
sepol_context_free(tmp_con);
|
sepol_port_free(tmp_record);
|
return STATUS_ERR;
|
}
|
|
/* Return the number of ports */
|
extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)),
|
const sepol_policydb_t * p, unsigned int *response)
|
{
|
|
unsigned int count = 0;
|
ocontext_t *c, *head;
|
const policydb_t *policydb = &p->p;
|
|
head = policydb->ocontexts[OCON_PORT];
|
for (c = head; c != NULL; c = c->next)
|
count++;
|
|
*response = count;
|
|
return STATUS_SUCCESS;
|
}
|
|
/* Check if a port exists */
|
int sepol_port_exists(sepol_handle_t * handle,
|
const sepol_policydb_t * p,
|
const sepol_port_key_t * key, int *response)
|
{
|
|
const policydb_t *policydb = &p->p;
|
ocontext_t *c, *head;
|
|
int low, high, proto;
|
const char *proto_str;
|
sepol_port_key_unpack(key, &low, &high, &proto);
|
proto_str = sepol_port_get_proto_str(proto);
|
proto = sepol2ipproto(handle, proto);
|
if (proto < 0)
|
goto err;
|
|
head = policydb->ocontexts[OCON_PORT];
|
for (c = head; c; c = c->next) {
|
int proto2 = c->u.port.protocol;
|
int low2 = c->u.port.low_port;
|
int high2 = c->u.port.high_port;
|
|
if (proto == proto2 && low2 == low && high2 == high) {
|
*response = 1;
|
return STATUS_SUCCESS;
|
}
|
}
|
|
*response = 0;
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not check if port range %u - %u (%s) exists",
|
low, high, proto_str);
|
return STATUS_ERR;
|
}
|
|
/* Query a port */
|
int sepol_port_query(sepol_handle_t * handle,
|
const sepol_policydb_t * p,
|
const sepol_port_key_t * key, sepol_port_t ** response)
|
{
|
|
const policydb_t *policydb = &p->p;
|
ocontext_t *c, *head;
|
|
int low, high, proto;
|
const char *proto_str;
|
sepol_port_key_unpack(key, &low, &high, &proto);
|
proto_str = sepol_port_get_proto_str(proto);
|
proto = sepol2ipproto(handle, proto);
|
if (proto < 0)
|
goto err;
|
|
head = policydb->ocontexts[OCON_PORT];
|
for (c = head; c; c = c->next) {
|
int proto2 = c->u.port.protocol;
|
int low2 = c->u.port.low_port;
|
int high2 = c->u.port.high_port;
|
|
if (proto == proto2 && low2 == low && high2 == high) {
|
if (port_to_record(handle, policydb, c, response) < 0)
|
goto err;
|
return STATUS_SUCCESS;
|
}
|
}
|
|
*response = NULL;
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not query port range %u - %u (%s)",
|
low, high, proto_str);
|
return STATUS_ERR;
|
|
}
|
|
/* Load a port into policy */
|
int sepol_port_modify(sepol_handle_t * handle,
|
sepol_policydb_t * p,
|
const sepol_port_key_t * key, const sepol_port_t * data)
|
{
|
|
policydb_t *policydb = &p->p;
|
ocontext_t *port = NULL;
|
|
int low, high, proto;
|
const char *proto_str;
|
|
sepol_port_key_unpack(key, &low, &high, &proto);
|
proto_str = sepol_port_get_proto_str(proto);
|
proto = sepol2ipproto(handle, proto);
|
if (proto < 0)
|
goto err;
|
|
if (port_from_record(handle, policydb, &port, data) < 0)
|
goto err;
|
|
/* Attach to context list */
|
port->next = policydb->ocontexts[OCON_PORT];
|
policydb->ocontexts[OCON_PORT] = port;
|
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not load port range %u - %u (%s)",
|
low, high, proto_str);
|
if (port != NULL) {
|
context_destroy(&port->context[0]);
|
free(port);
|
}
|
return STATUS_ERR;
|
}
|
|
int sepol_port_iterate(sepol_handle_t * handle,
|
const sepol_policydb_t * p,
|
int (*fn) (const sepol_port_t * port,
|
void *fn_arg), void *arg)
|
{
|
|
const policydb_t *policydb = &p->p;
|
ocontext_t *c, *head;
|
sepol_port_t *port = NULL;
|
|
head = policydb->ocontexts[OCON_PORT];
|
for (c = head; c; c = c->next) {
|
int status;
|
|
if (port_to_record(handle, policydb, c, &port) < 0)
|
goto err;
|
|
/* Invoke handler */
|
status = fn(port, arg);
|
if (status < 0)
|
goto err;
|
|
sepol_port_free(port);
|
port = NULL;
|
|
/* Handler requested exit */
|
if (status > 0)
|
break;
|
}
|
|
return STATUS_SUCCESS;
|
|
err:
|
ERR(handle, "could not iterate over ports");
|
sepol_port_free(port);
|
return STATUS_ERR;
|
}
|