1 #include <netinet/in.h>
2 #include <arpa/inet.h>
3 #include <stdlib.h>
4 
5 #include "debug.h"
6 #include "context.h"
7 #include "handle.h"
8 
9 #include <sepol/policydb/policydb.h>
10 #include "node_internal.h"
11 
12 /* Create a low level node structure from
13  * a high level representation */
node_from_record(sepol_handle_t * handle,const policydb_t * policydb,ocontext_t ** node,const sepol_node_t * data)14 static int node_from_record(sepol_handle_t * handle,
15 			    const policydb_t * policydb,
16 			    ocontext_t ** node, const sepol_node_t * data)
17 {
18 
19 	ocontext_t *tmp_node = NULL;
20 	context_struct_t *tmp_con = NULL;
21 	char *addr_buf = NULL, *mask_buf = NULL;
22 
23 	tmp_node = (ocontext_t *) calloc(1, sizeof(ocontext_t));
24 	if (!tmp_node)
25 		goto omem;
26 
27 	size_t addr_bsize, mask_bsize;
28 
29 	/* Address and netmask */
30 	if (sepol_node_get_addr_bytes(handle, data, &addr_buf, &addr_bsize) < 0)
31 		goto err;
32 	if (sepol_node_get_mask_bytes(handle, data, &mask_buf, &mask_bsize) < 0)
33 		goto err;
34 
35 	int proto = sepol_node_get_proto(data);
36 
37 	switch (proto) {
38 	case SEPOL_PROTO_IP4:
39 		memcpy(&tmp_node->u.node.addr, addr_buf, addr_bsize);
40 		memcpy(&tmp_node->u.node.mask, mask_buf, mask_bsize);
41 		break;
42 	case SEPOL_PROTO_IP6:
43 		memcpy(tmp_node->u.node6.addr, addr_buf, addr_bsize);
44 		memcpy(tmp_node->u.node6.mask, mask_buf, mask_bsize);
45 		break;
46 	default:
47 		ERR(handle, "unsupported protocol %u", proto);
48 		goto err;
49 	}
50 	free(addr_buf);
51 	free(mask_buf);
52 	addr_buf = NULL;
53 	mask_buf = NULL;
54 
55 	/* Context */
56 	if (context_from_record(handle, policydb, &tmp_con,
57 				sepol_node_get_con(data)) < 0)
58 		goto err;
59 	context_cpy(&tmp_node->context[0], tmp_con);
60 	context_destroy(tmp_con);
61 	free(tmp_con);
62 	tmp_con = NULL;
63 
64 	*node = tmp_node;
65 	return STATUS_SUCCESS;
66 
67       omem:
68 	ERR(handle, "out of memory");
69 
70       err:
71 	if (tmp_node != NULL) {
72 		context_destroy(&tmp_node->context[0]);
73 		free(tmp_node);
74 	}
75 	context_destroy(tmp_con);
76 	free(tmp_con);
77 	free(addr_buf);
78 	free(mask_buf);
79 	ERR(handle, "could not create node structure");
80 	return STATUS_ERR;
81 }
82 
node_to_record(sepol_handle_t * handle,const policydb_t * policydb,ocontext_t * node,int proto,sepol_node_t ** record)83 static int node_to_record(sepol_handle_t * handle,
84 			  const policydb_t * policydb,
85 			  ocontext_t * node, int proto, sepol_node_t ** record)
86 {
87 
88 	context_struct_t *con = &node->context[0];
89 
90 	sepol_context_t *tmp_con = NULL;
91 	sepol_node_t *tmp_record = NULL;
92 
93 	if (sepol_node_create(handle, &tmp_record) < 0)
94 		goto err;
95 
96 	sepol_node_set_proto(tmp_record, proto);
97 
98 	switch (proto) {
99 
100 	case SEPOL_PROTO_IP4:
101 		if (sepol_node_set_addr_bytes(handle, tmp_record,
102 					      (const char *)&node->u.node.addr,
103 					      4) < 0)
104 			goto err;
105 
106 		if (sepol_node_set_mask_bytes(handle, tmp_record,
107 					      (const char *)&node->u.node.mask,
108 					      4) < 0)
109 			goto err;
110 		break;
111 
112 	case SEPOL_PROTO_IP6:
113 		if (sepol_node_set_addr_bytes(handle, tmp_record,
114 					      (const char *)&node->u.node6.addr,
115 					      16) < 0)
116 			goto err;
117 
118 		if (sepol_node_set_mask_bytes(handle, tmp_record,
119 					      (const char *)&node->u.node6.mask,
120 					      16) < 0)
121 			goto err;
122 		break;
123 
124 	default:
125 		ERR(handle, "unsupported protocol %u", proto);
126 		goto err;
127 	}
128 
129 	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
130 		goto err;
131 
132 	if (sepol_node_set_con(handle, tmp_record, tmp_con) < 0)
133 		goto err;
134 
135 	sepol_context_free(tmp_con);
136 	*record = tmp_record;
137 	return STATUS_SUCCESS;
138 
139       err:
140 	ERR(handle, "could not convert node to record");
141 	sepol_context_free(tmp_con);
142 	sepol_node_free(tmp_record);
143 	return STATUS_ERR;
144 }
145 
146 /* Return the number of nodes */
sepol_node_count(sepol_handle_t * handle,const sepol_policydb_t * p,unsigned int * response)147 extern int sepol_node_count(sepol_handle_t * handle __attribute__ ((unused)),
148 			    const sepol_policydb_t * p, unsigned int *response)
149 {
150 
151 	unsigned int count = 0;
152 	ocontext_t *c, *head;
153 	const policydb_t *policydb = &p->p;
154 
155 	head = policydb->ocontexts[OCON_NODE];
156 	for (c = head; c != NULL; c = c->next)
157 		count++;
158 
159 	head = policydb->ocontexts[OCON_NODE6];
160 	for (c = head; c != NULL; c = c->next)
161 		count++;
162 
163 	*response = count;
164 
165 	handle = NULL;
166 	return STATUS_SUCCESS;
167 }
168 
169 /* Check if a node exists */
sepol_node_exists(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_node_key_t * key,int * response)170 int sepol_node_exists(sepol_handle_t * handle,
171 		      const sepol_policydb_t * p,
172 		      const sepol_node_key_t * key, int *response)
173 {
174 
175 	const policydb_t *policydb = &p->p;
176 	ocontext_t *c, *head;
177 
178 	int proto;
179 	const char *addr, *mask;
180 	sepol_node_key_unpack(key, &addr, &mask, &proto);
181 
182 	switch (proto) {
183 
184 	case SEPOL_PROTO_IP4:
185 		{
186 			head = policydb->ocontexts[OCON_NODE];
187 			for (c = head; c; c = c->next) {
188 				unsigned int *addr2 = &c->u.node.addr;
189 				unsigned int *mask2 = &c->u.node.mask;
190 
191 				if (!memcmp(addr, addr2, 4) &&
192 				    !memcmp(mask, mask2, 4)) {
193 
194 					*response = 1;
195 					return STATUS_SUCCESS;
196 				}
197 			}
198 			break;
199 		}
200 	case SEPOL_PROTO_IP6:
201 		{
202 			head = policydb->ocontexts[OCON_NODE6];
203 			for (c = head; c; c = c->next) {
204 				unsigned int *addr2 = c->u.node6.addr;
205 				unsigned int *mask2 = c->u.node6.mask;
206 
207 				if (!memcmp(addr, addr2, 16) &&
208 				    !memcmp(mask, mask2, 16)) {
209 					*response = 1;
210 					return STATUS_SUCCESS;
211 				}
212 			}
213 			break;
214 		}
215 	default:
216 		ERR(handle, "unsupported protocol %u", proto);
217 		goto err;
218 	}
219 
220 	*response = 0;
221 	return STATUS_SUCCESS;
222 
223       err:
224 	ERR(handle, "could not check if node %s/%s (%s) exists",
225 	    addr, mask, sepol_node_get_proto_str(proto));
226 	return STATUS_ERR;
227 }
228 
229 /* Query a node */
sepol_node_query(sepol_handle_t * handle,const sepol_policydb_t * p,const sepol_node_key_t * key,sepol_node_t ** response)230 int sepol_node_query(sepol_handle_t * handle,
231 		     const sepol_policydb_t * p,
232 		     const sepol_node_key_t * key, sepol_node_t ** response)
233 {
234 
235 	const policydb_t *policydb = &p->p;
236 	ocontext_t *c, *head;
237 
238 	int proto;
239 	const char *addr, *mask;
240 	sepol_node_key_unpack(key, &addr, &mask, &proto);
241 
242 	switch (proto) {
243 
244 	case SEPOL_PROTO_IP4:
245 		{
246 			head = policydb->ocontexts[OCON_NODE];
247 			for (c = head; c; c = c->next) {
248 				unsigned int *addr2 = &c->u.node.addr;
249 				unsigned int *mask2 = &c->u.node.mask;
250 
251 				if (!memcmp(addr, addr2, 4) &&
252 				    !memcmp(mask, mask2, 4)) {
253 
254 					if (node_to_record(handle, policydb,
255 							   c, SEPOL_PROTO_IP4,
256 							   response) < 0)
257 						goto err;
258 					return STATUS_SUCCESS;
259 				}
260 			}
261 			break;
262 		}
263 	case SEPOL_PROTO_IP6:
264 		{
265 			head = policydb->ocontexts[OCON_NODE6];
266 			for (c = head; c; c = c->next) {
267 				unsigned int *addr2 = c->u.node6.addr;
268 				unsigned int *mask2 = c->u.node6.mask;
269 
270 				if (!memcmp(addr, addr2, 16) &&
271 				    !memcmp(mask, mask2, 16)) {
272 
273 					if (node_to_record(handle, policydb,
274 							   c, SEPOL_PROTO_IP6,
275 							   response) < 0)
276 						goto err;
277 				}
278 			}
279 			break;
280 		}
281 	default:
282 		ERR(handle, "unsupported protocol %u", proto);
283 		goto err;
284 	}
285 	*response = NULL;
286 	return STATUS_SUCCESS;
287 
288       err:
289 	ERR(handle, "could not query node %s/%s (%s)",
290 	    addr, mask, sepol_node_get_proto_str(proto));
291 	return STATUS_ERR;
292 
293 }
294 
295 /* Load a node into policy */
sepol_node_modify(sepol_handle_t * handle,sepol_policydb_t * p,const sepol_node_key_t * key,const sepol_node_t * data)296 int sepol_node_modify(sepol_handle_t * handle,
297 		      sepol_policydb_t * p,
298 		      const sepol_node_key_t * key, const sepol_node_t * data)
299 {
300 
301 	policydb_t *policydb = &p->p;
302 	ocontext_t *node = NULL;
303 
304 	int proto;
305 	const char *addr, *mask;
306 
307 	sepol_node_key_unpack(key, &addr, &mask, &proto);
308 
309 	if (node_from_record(handle, policydb, &node, data) < 0)
310 		goto err;
311 
312 	switch (proto) {
313 
314 	case SEPOL_PROTO_IP4:
315 		{
316 			/* Attach to context list */
317 			node->next = policydb->ocontexts[OCON_NODE];
318 			policydb->ocontexts[OCON_NODE] = node;
319 			break;
320 		}
321 	case SEPOL_PROTO_IP6:
322 		{
323 			/* Attach to context list */
324 			node->next = policydb->ocontexts[OCON_NODE6];
325 			policydb->ocontexts[OCON_NODE6] = node;
326 			break;
327 		}
328 	default:
329 		ERR(handle, "unsupported protocol %u", proto);
330 		goto err;
331 	}
332 
333 	return STATUS_SUCCESS;
334 
335       err:
336 	ERR(handle, "could not load node %s/%s (%s)",
337 	    addr, mask, sepol_node_get_proto_str(proto));
338 	if (node != NULL) {
339 		context_destroy(&node->context[0]);
340 		free(node);
341 	}
342 	return STATUS_ERR;
343 }
344 
sepol_node_iterate(sepol_handle_t * handle,const sepol_policydb_t * p,int (* fn)(const sepol_node_t * node,void * fn_arg),void * arg)345 int sepol_node_iterate(sepol_handle_t * handle,
346 		       const sepol_policydb_t * p,
347 		       int (*fn) (const sepol_node_t * node,
348 				  void *fn_arg), void *arg)
349 {
350 
351 	const policydb_t *policydb = &p->p;
352 	ocontext_t *c, *head;
353 	sepol_node_t *node = NULL;
354 	int status;
355 
356 	head = policydb->ocontexts[OCON_NODE];
357 	for (c = head; c; c = c->next) {
358 		if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP4, &node)
359 		    < 0)
360 			goto err;
361 
362 		/* Invoke handler */
363 		status = fn(node, arg);
364 		if (status < 0)
365 			goto err;
366 
367 		sepol_node_free(node);
368 		node = NULL;
369 
370 		/* Handler requested exit */
371 		if (status > 0)
372 			break;
373 	}
374 
375 	head = policydb->ocontexts[OCON_NODE6];
376 	for (c = head; c; c = c->next) {
377 		if (node_to_record(handle, policydb, c, SEPOL_PROTO_IP6, &node)
378 		    < 0)
379 			goto err;
380 
381 		/* Invoke handler */
382 		status = fn(node, arg);
383 		if (status < 0)
384 			goto err;
385 
386 		sepol_node_free(node);
387 		node = NULL;
388 
389 		/* Handler requested exit */
390 		if (status > 0)
391 			break;
392 	}
393 
394 	return STATUS_SUCCESS;
395 
396       err:
397 	ERR(handle, "could not iterate over nodes");
398 	sepol_node_free(node);
399 	return STATUS_ERR;
400 }
401