nodes.c revision 747a440fdd5b32c16739ecbd76367eb2a582fe82
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	return STATUS_SUCCESS;
166}
167
168/* Check if a node exists */
169int sepol_node_exists(sepol_handle_t * handle,
170		      const sepol_policydb_t * p,
171		      const sepol_node_key_t * key, int *response)
172{
173
174	const policydb_t *policydb = &p->p;
175	ocontext_t *c, *head;
176
177	int proto;
178	const char *addr, *mask;
179	sepol_node_key_unpack(key, &addr, &mask, &proto);
180
181	switch (proto) {
182
183	case SEPOL_PROTO_IP4:
184		{
185			head = policydb->ocontexts[OCON_NODE];
186			for (c = head; c; c = c->next) {
187				unsigned int *addr2 = &c->u.node.addr;
188				unsigned int *mask2 = &c->u.node.mask;
189
190				if (!memcmp(addr, addr2, 4) &&
191				    !memcmp(mask, mask2, 4)) {
192
193					*response = 1;
194					return STATUS_SUCCESS;
195				}
196			}
197			break;
198		}
199	case SEPOL_PROTO_IP6:
200		{
201			head = policydb->ocontexts[OCON_NODE6];
202			for (c = head; c; c = c->next) {
203				unsigned int *addr2 = c->u.node6.addr;
204				unsigned int *mask2 = c->u.node6.mask;
205
206				if (!memcmp(addr, addr2, 16) &&
207				    !memcmp(mask, mask2, 16)) {
208					*response = 1;
209					return STATUS_SUCCESS;
210				}
211			}
212			break;
213		}
214	default:
215		ERR(handle, "unsupported protocol %u", proto);
216		goto err;
217	}
218
219	*response = 0;
220	return STATUS_SUCCESS;
221
222      err:
223	ERR(handle, "could not check if node %s/%s (%s) exists",
224	    addr, mask, sepol_node_get_proto_str(proto));
225	return STATUS_ERR;
226}
227
228/* Query a node */
229int sepol_node_query(sepol_handle_t * handle,
230		     const sepol_policydb_t * p,
231		     const sepol_node_key_t * key, sepol_node_t ** response)
232{
233
234	const policydb_t *policydb = &p->p;
235	ocontext_t *c, *head;
236
237	int proto;
238	const char *addr, *mask;
239	sepol_node_key_unpack(key, &addr, &mask, &proto);
240
241	switch (proto) {
242
243	case SEPOL_PROTO_IP4:
244		{
245			head = policydb->ocontexts[OCON_NODE];
246			for (c = head; c; c = c->next) {
247				unsigned int *addr2 = &c->u.node.addr;
248				unsigned int *mask2 = &c->u.node.mask;
249
250				if (!memcmp(addr, addr2, 4) &&
251				    !memcmp(mask, mask2, 4)) {
252
253					if (node_to_record(handle, policydb,
254							   c, SEPOL_PROTO_IP4,
255							   response) < 0)
256						goto err;
257					return STATUS_SUCCESS;
258				}
259			}
260			break;
261		}
262	case SEPOL_PROTO_IP6:
263		{
264			head = policydb->ocontexts[OCON_NODE6];
265			for (c = head; c; c = c->next) {
266				unsigned int *addr2 = c->u.node6.addr;
267				unsigned int *mask2 = c->u.node6.mask;
268
269				if (!memcmp(addr, addr2, 16) &&
270				    !memcmp(mask, mask2, 16)) {
271
272					if (node_to_record(handle, policydb,
273							   c, SEPOL_PROTO_IP6,
274							   response) < 0)
275						goto err;
276					return STATUS_SUCCESS;
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