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