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
14static 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
30static 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 */
48static 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
107static 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 */
150extern 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 */
168int 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 */
206int 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 */
246int 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
282int 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