Home | History | Annotate | Download | only in src
      1 #include <netinet/in.h>
      2 #ifndef IPPROTO_DCCP
      3 #define IPPROTO_DCCP 33
      4 #endif
      5 #include <stdlib.h>
      6 
      7 #include "debug.h"
      8 #include "context.h"
      9 #include "handle.h"
     10 
     11 #include <sepol/policydb/policydb.h>
     12 #include "port_internal.h"
     13 
     14 static inline int sepol2ipproto(sepol_handle_t * handle, int proto)
     15 {
     16 
     17 	switch (proto) {
     18 	case SEPOL_PROTO_TCP:
     19 		return IPPROTO_TCP;
     20 	case SEPOL_PROTO_UDP:
     21 		return IPPROTO_UDP;
     22 	case SEPOL_PROTO_DCCP:
     23 		return IPPROTO_DCCP;
     24 	default:
     25 		ERR(handle, "unsupported protocol %u", proto);
     26 		return STATUS_ERR;
     27 	}
     28 }
     29 
     30 static inline int ipproto2sepol(sepol_handle_t * handle, int proto)
     31 {
     32 
     33 	switch (proto) {
     34 	case IPPROTO_TCP:
     35 		return SEPOL_PROTO_TCP;
     36 	case IPPROTO_UDP:
     37 		return SEPOL_PROTO_UDP;
     38 	case IPPROTO_DCCP:
     39 		return SEPOL_PROTO_DCCP;
     40 	default:
     41 		ERR(handle, "invalid protocol %u " "found in policy", proto);
     42 		return STATUS_ERR;
     43 	}
     44 }
     45 
     46 /* Create a low level port structure from
     47  * a high level representation */
     48 static int port_from_record(sepol_handle_t * handle,
     49 			    const policydb_t * policydb,
     50 			    ocontext_t ** port, const sepol_port_t * data)
     51 {
     52 
     53 	ocontext_t *tmp_port = NULL;
     54 	context_struct_t *tmp_con = NULL;
     55 	int tmp_proto;
     56 
     57 	int low = sepol_port_get_low(data);
     58 	int high = sepol_port_get_high(data);
     59 	int proto = sepol_port_get_proto(data);
     60 
     61 	tmp_port = (ocontext_t *) calloc(1, sizeof(ocontext_t));
     62 	if (!tmp_port)
     63 		goto omem;
     64 
     65 	/* Process protocol */
     66 	tmp_proto = sepol2ipproto(handle, proto);
     67 	if (tmp_proto < 0)
     68 		goto err;
     69 	tmp_port->u.port.protocol = tmp_proto;
     70 
     71 	/* Port range */
     72 	tmp_port->u.port.low_port = low;
     73 	tmp_port->u.port.high_port = high;
     74 	if (tmp_port->u.port.low_port > tmp_port->u.port.high_port) {
     75 		ERR(handle, "low port %d exceeds high port %d",
     76 		    tmp_port->u.port.low_port, tmp_port->u.port.high_port);
     77 		goto err;
     78 	}
     79 
     80 	/* Context */
     81 	if (context_from_record(handle, policydb, &tmp_con,
     82 				sepol_port_get_con(data)) < 0)
     83 		goto err;
     84 	context_cpy(&tmp_port->context[0], tmp_con);
     85 	context_destroy(tmp_con);
     86 	free(tmp_con);
     87 	tmp_con = NULL;
     88 
     89 	*port = tmp_port;
     90 	return STATUS_SUCCESS;
     91 
     92       omem:
     93 	ERR(handle, "out of memory");
     94 
     95       err:
     96 	if (tmp_port != NULL) {
     97 		context_destroy(&tmp_port->context[0]);
     98 		free(tmp_port);
     99 	}
    100 	context_destroy(tmp_con);
    101 	free(tmp_con);
    102 	ERR(handle, "could not create port structure for range %u:%u (%s)",
    103 	    low, high, sepol_port_get_proto_str(proto));
    104 	return STATUS_ERR;
    105 }
    106 
    107 static int port_to_record(sepol_handle_t * handle,
    108 			  const policydb_t * policydb,
    109 			  ocontext_t * port, sepol_port_t ** record)
    110 {
    111 
    112 	int proto = port->u.port.protocol;
    113 	int low = port->u.port.low_port;
    114 	int high = port->u.port.high_port;
    115 	context_struct_t *con = &port->context[0];
    116 	int rec_proto = -1;
    117 
    118 	sepol_context_t *tmp_con = NULL;
    119 	sepol_port_t *tmp_record = NULL;
    120 
    121 	if (sepol_port_create(handle, &tmp_record) < 0)
    122 		goto err;
    123 
    124 	rec_proto = ipproto2sepol(handle, proto);
    125 	if (rec_proto < 0)
    126 		goto err;
    127 
    128 	sepol_port_set_proto(tmp_record, rec_proto);
    129 	sepol_port_set_range(tmp_record, low, high);
    130 
    131 	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
    132 		goto err;
    133 
    134 	if (sepol_port_set_con(handle, tmp_record, tmp_con) < 0)
    135 		goto err;
    136 
    137 	sepol_context_free(tmp_con);
    138 	*record = tmp_record;
    139 	return STATUS_SUCCESS;
    140 
    141       err:
    142 	ERR(handle, "could not convert port range %u - %u (%s) "
    143 	    "to record", low, high, sepol_port_get_proto_str(rec_proto));
    144 	sepol_context_free(tmp_con);
    145 	sepol_port_free(tmp_record);
    146 	return STATUS_ERR;
    147 }
    148 
    149 /* Return the number of ports */
    150 extern int sepol_port_count(sepol_handle_t * handle __attribute__ ((unused)),
    151 			    const sepol_policydb_t * p, unsigned int *response)
    152 {
    153 
    154 	unsigned int count = 0;
    155 	ocontext_t *c, *head;
    156 	const policydb_t *policydb = &p->p;
    157 
    158 	head = policydb->ocontexts[OCON_PORT];
    159 	for (c = head; c != NULL; c = c->next)
    160 		count++;
    161 
    162 	*response = count;
    163 
    164 	return STATUS_SUCCESS;
    165 }
    166 
    167 /* Check if a port exists */
    168 int sepol_port_exists(sepol_handle_t * handle,
    169 		      const sepol_policydb_t * p,
    170 		      const sepol_port_key_t * key, int *response)
    171 {
    172 
    173 	const policydb_t *policydb = &p->p;
    174 	ocontext_t *c, *head;
    175 
    176 	int low, high, proto;
    177 	const char *proto_str;
    178 	sepol_port_key_unpack(key, &low, &high, &proto);
    179 	proto_str = sepol_port_get_proto_str(proto);
    180 	proto = sepol2ipproto(handle, proto);
    181 	if (proto < 0)
    182 		goto err;
    183 
    184 	head = policydb->ocontexts[OCON_PORT];
    185 	for (c = head; c; c = c->next) {
    186 		int proto2 = c->u.port.protocol;
    187 		int low2 = c->u.port.low_port;
    188 		int high2 = c->u.port.high_port;
    189 
    190 		if (proto == proto2 && low2 == low && high2 == high) {
    191 			*response = 1;
    192 			return STATUS_SUCCESS;
    193 		}
    194 	}
    195 
    196 	*response = 0;
    197 	return STATUS_SUCCESS;
    198 
    199       err:
    200 	ERR(handle, "could not check if port range %u - %u (%s) exists",
    201 	    low, high, proto_str);
    202 	return STATUS_ERR;
    203 }
    204 
    205 /* Query a port */
    206 int sepol_port_query(sepol_handle_t * handle,
    207 		     const sepol_policydb_t * p,
    208 		     const sepol_port_key_t * key, sepol_port_t ** response)
    209 {
    210 
    211 	const policydb_t *policydb = &p->p;
    212 	ocontext_t *c, *head;
    213 
    214 	int low, high, proto;
    215 	const char *proto_str;
    216 	sepol_port_key_unpack(key, &low, &high, &proto);
    217 	proto_str = sepol_port_get_proto_str(proto);
    218 	proto = sepol2ipproto(handle, proto);
    219 	if (proto < 0)
    220 		goto err;
    221 
    222 	head = policydb->ocontexts[OCON_PORT];
    223 	for (c = head; c; c = c->next) {
    224 		int proto2 = c->u.port.protocol;
    225 		int low2 = c->u.port.low_port;
    226 		int high2 = c->u.port.high_port;
    227 
    228 		if (proto == proto2 && low2 == low && high2 == high) {
    229 			if (port_to_record(handle, policydb, c, response) < 0)
    230 				goto err;
    231 			return STATUS_SUCCESS;
    232 		}
    233 	}
    234 
    235 	*response = NULL;
    236 	return STATUS_SUCCESS;
    237 
    238       err:
    239 	ERR(handle, "could not query port range %u - %u (%s)",
    240 	    low, high, proto_str);
    241 	return STATUS_ERR;
    242 
    243 }
    244 
    245 /* Load a port into policy */
    246 int sepol_port_modify(sepol_handle_t * handle,
    247 		      sepol_policydb_t * p,
    248 		      const sepol_port_key_t * key, const sepol_port_t * data)
    249 {
    250 
    251 	policydb_t *policydb = &p->p;
    252 	ocontext_t *port = NULL;
    253 
    254 	int low, high, proto;
    255 	const char *proto_str;
    256 
    257 	sepol_port_key_unpack(key, &low, &high, &proto);
    258 	proto_str = sepol_port_get_proto_str(proto);
    259 	proto = sepol2ipproto(handle, proto);
    260 	if (proto < 0)
    261 		goto err;
    262 
    263 	if (port_from_record(handle, policydb, &port, data) < 0)
    264 		goto err;
    265 
    266 	/* Attach to context list */
    267 	port->next = policydb->ocontexts[OCON_PORT];
    268 	policydb->ocontexts[OCON_PORT] = port;
    269 
    270 	return STATUS_SUCCESS;
    271 
    272       err:
    273 	ERR(handle, "could not load port range %u - %u (%s)",
    274 	    low, high, proto_str);
    275 	if (port != NULL) {
    276 		context_destroy(&port->context[0]);
    277 		free(port);
    278 	}
    279 	return STATUS_ERR;
    280 }
    281 
    282 int sepol_port_iterate(sepol_handle_t * handle,
    283 		       const sepol_policydb_t * p,
    284 		       int (*fn) (const sepol_port_t * port,
    285 				  void *fn_arg), void *arg)
    286 {
    287 
    288 	const policydb_t *policydb = &p->p;
    289 	ocontext_t *c, *head;
    290 	sepol_port_t *port = NULL;
    291 
    292 	head = policydb->ocontexts[OCON_PORT];
    293 	for (c = head; c; c = c->next) {
    294 		int status;
    295 
    296 		if (port_to_record(handle, policydb, c, &port) < 0)
    297 			goto err;
    298 
    299 		/* Invoke handler */
    300 		status = fn(port, arg);
    301 		if (status < 0)
    302 			goto err;
    303 
    304 		sepol_port_free(port);
    305 		port = NULL;
    306 
    307 		/* Handler requested exit */
    308 		if (status > 0)
    309 			break;
    310 	}
    311 
    312 	return STATUS_SUCCESS;
    313 
    314       err:
    315 	ERR(handle, "could not iterate over ports");
    316 	sepol_port_free(port);
    317 	return STATUS_ERR;
    318 }
    319