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
11static 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
25static 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 */
41static 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
100static 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 */
143extern 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 */
162int 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 */
200int 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 */
240int 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
276int 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