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