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 
sepol2ipproto(sepol_handle_t * handle,int proto)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 
ipproto2sepol(sepol_handle_t * handle,int proto)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 */
port_from_record(sepol_handle_t * handle,const policydb_t * policydb,ocontext_t ** port,const sepol_port_t * data)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 
port_to_record(sepol_handle_t * handle,const policydb_t * policydb,ocontext_t * port,sepol_port_t ** record)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 */
sepol_port_count(sepol_handle_t * handle,const sepol_policydb_t * p,unsigned int * response)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 */
sepol_port_exists(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_port_key_t * key,int * response)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 */
sepol_port_query(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_port_key_t * key,sepol_port_t ** response)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 */
sepol_port_modify(sepol_handle_t * handle,sepol_policydb_t * p,const sepol_port_key_t * key,const sepol_port_t * data)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 
sepol_port_iterate(sepol_handle_t * handle,const sepol_policydb_t * p,int (* fn)(const sepol_port_t * port,void * fn_arg),void * arg)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