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 */
14static 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
83static 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 */
147extern 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 */
170int 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 */
230int 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 */
296int 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
345int 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