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/ibpkey_record.h>
9#include <sepol/policydb/policydb.h>
10#include "ibpkey_internal.h"
11
12/* Create a low level ibpkey structure from
13 * a high level representation
14 */
15static int ibpkey_from_record(sepol_handle_t *handle,
16			      const policydb_t *policydb,
17			      ocontext_t **ibpkey, const sepol_ibpkey_t *data)
18{
19	ocontext_t *tmp_ibpkey = NULL;
20	context_struct_t *tmp_con = NULL;
21	char *subnet_prefix_buf = NULL;
22	int low = sepol_ibpkey_get_low(data);
23	int high = sepol_ibpkey_get_high(data);
24
25	tmp_ibpkey = (ocontext_t *)calloc(1, sizeof(*tmp_ibpkey));
26	if (!tmp_ibpkey)
27		goto omem;
28
29	tmp_ibpkey->u.ibpkey.subnet_prefix = sepol_ibpkey_get_subnet_prefix_bytes(data);
30
31	/* Pkey range */
32	tmp_ibpkey->u.ibpkey.low_pkey = low;
33	tmp_ibpkey->u.ibpkey.high_pkey = high;
34	if (tmp_ibpkey->u.ibpkey.low_pkey > tmp_ibpkey->u.ibpkey.high_pkey) {
35		ERR(handle, "low ibpkey %d exceeds high ibpkey %d",
36		    tmp_ibpkey->u.ibpkey.low_pkey, tmp_ibpkey->u.ibpkey.high_pkey);
37		goto err;
38	}
39
40	/* Context */
41	if (context_from_record(handle, policydb, &tmp_con,
42				sepol_ibpkey_get_con(data)) < 0)
43		goto err;
44	context_cpy(&tmp_ibpkey->context[0], tmp_con);
45	context_destroy(tmp_con);
46	free(tmp_con);
47	tmp_con = NULL;
48
49	*ibpkey = tmp_ibpkey;
50	return STATUS_SUCCESS;
51
52omem:
53	ERR(handle, "out of memory");
54
55err:
56	if (tmp_ibpkey) {
57		context_destroy(&tmp_ibpkey->context[0]);
58		free(tmp_ibpkey);
59	}
60	context_destroy(tmp_con);
61	free(tmp_con);
62	free(subnet_prefix_buf);
63	ERR(handle, "could not create ibpkey structure");
64	return STATUS_ERR;
65}
66
67static int ibpkey_to_record(sepol_handle_t *handle,
68			    const policydb_t *policydb,
69			    ocontext_t *ibpkey, sepol_ibpkey_t **record)
70{
71	context_struct_t *con = &ibpkey->context[0];
72	sepol_context_t *tmp_con = NULL;
73	sepol_ibpkey_t *tmp_record = NULL;
74
75	if (sepol_ibpkey_create(handle, &tmp_record) < 0)
76		goto err;
77
78	sepol_ibpkey_set_subnet_prefix_bytes(tmp_record,
79					     ibpkey->u.ibpkey.subnet_prefix);
80
81	sepol_ibpkey_set_range(tmp_record, ibpkey->u.ibpkey.low_pkey,
82			       ibpkey->u.ibpkey.high_pkey);
83
84	if (context_to_record(handle, policydb, con, &tmp_con) < 0)
85		goto err;
86
87	if (sepol_ibpkey_set_con(handle, tmp_record, tmp_con) < 0)
88		goto err;
89
90	sepol_context_free(tmp_con);
91	*record = tmp_record;
92	return STATUS_SUCCESS;
93
94err:
95	ERR(handle, "could not convert ibpkey to record");
96	sepol_context_free(tmp_con);
97	sepol_ibpkey_free(tmp_record);
98	return STATUS_ERR;
99}
100
101/* Return the number of ibpkeys */
102extern int sepol_ibpkey_count(sepol_handle_t *handle __attribute__ ((unused)),
103			      const sepol_policydb_t *p, unsigned int *response)
104{
105	unsigned int count = 0;
106	ocontext_t *c, *head;
107	const policydb_t *policydb = &p->p;
108
109	head = policydb->ocontexts[OCON_IBPKEY];
110	for (c = head; c; c = c->next)
111		count++;
112
113	*response = count;
114
115	return STATUS_SUCCESS;
116}
117
118/* Check if a ibpkey exists */
119int sepol_ibpkey_exists(sepol_handle_t *handle __attribute__ ((unused)),
120			const sepol_policydb_t *p,
121			const sepol_ibpkey_key_t *key, int *response)
122{
123	const policydb_t *policydb = &p->p;
124	ocontext_t *c, *head;
125	int low, high;
126	uint64_t subnet_prefix;
127
128	sepol_ibpkey_key_unpack(key, &subnet_prefix, &low, &high);
129
130	head = policydb->ocontexts[OCON_IBPKEY];
131	for (c = head; c; c = c->next) {
132		uint64_t subnet_prefix2 = c->u.ibpkey.subnet_prefix;
133		uint16_t low2 = c->u.ibpkey.low_pkey;
134		uint16_t high2 = c->u.ibpkey.high_pkey;
135
136		if (low2 == low &&
137		    high2 == high &&
138		    subnet_prefix == subnet_prefix2) {
139			*response = 1;
140			return STATUS_SUCCESS;
141		}
142	}
143
144	*response = 0;
145	return STATUS_SUCCESS;
146}
147
148/* Query a ibpkey */
149int sepol_ibpkey_query(sepol_handle_t *handle,
150		       const sepol_policydb_t *p,
151		       const sepol_ibpkey_key_t *key, sepol_ibpkey_t **response)
152{
153	const policydb_t *policydb = &p->p;
154	ocontext_t *c, *head;
155	int low, high;
156	uint64_t subnet_prefix;
157
158	sepol_ibpkey_key_unpack(key, &subnet_prefix, &low, &high);
159
160	head = policydb->ocontexts[OCON_IBPKEY];
161	for (c = head; c; c = c->next) {
162		uint64_t subnet_prefix2 = c->u.ibpkey.subnet_prefix;
163		int low2 = c->u.ibpkey.low_pkey;
164		int high2 = c->u.ibpkey.high_pkey;
165
166		if (low2 == low &&
167		    high2 == high &&
168		    subnet_prefix == subnet_prefix2) {
169			if (ibpkey_to_record(handle, policydb, c, response) < 0)
170				goto err;
171			return STATUS_SUCCESS;
172		}
173	}
174
175	*response = NULL;
176	return STATUS_SUCCESS;
177
178err:
179	ERR(handle, "could not query ibpkey subnet prefix: %#lx range %u - %u exists",
180	    subnet_prefix, low, high);
181	return STATUS_ERR;
182}
183
184/* Load a ibpkey into policy */
185int sepol_ibpkey_modify(sepol_handle_t *handle,
186			sepol_policydb_t *p,
187			const sepol_ibpkey_key_t *key, const sepol_ibpkey_t *data)
188{
189	policydb_t *policydb = &p->p;
190	ocontext_t *ibpkey = NULL;
191	int low, high;
192	uint64_t subnet_prefix;
193
194	sepol_ibpkey_key_unpack(key, &subnet_prefix, &low, &high);
195
196	if (ibpkey_from_record(handle, policydb, &ibpkey, data) < 0)
197		goto err;
198
199	/* Attach to context list */
200	ibpkey->next = policydb->ocontexts[OCON_IBPKEY];
201	policydb->ocontexts[OCON_IBPKEY] = ibpkey;
202
203	return STATUS_SUCCESS;
204
205err:
206	ERR(handle, "could not load ibpkey subnet prefix: %#lx range %u - %u exists",
207	    subnet_prefix, low, high);
208	if (ibpkey) {
209		context_destroy(&ibpkey->context[0]);
210		free(ibpkey);
211	}
212	return STATUS_ERR;
213}
214
215int sepol_ibpkey_iterate(sepol_handle_t *handle,
216			 const sepol_policydb_t *p,
217			 int (*fn)(const sepol_ibpkey_t *ibpkey,
218				   void *fn_arg), void *arg)
219{
220	const policydb_t *policydb = &p->p;
221	ocontext_t *c, *head;
222	sepol_ibpkey_t *ibpkey = NULL;
223
224	head = policydb->ocontexts[OCON_IBPKEY];
225	for (c = head; c; c = c->next) {
226		int status;
227
228		if (ibpkey_to_record(handle, policydb, c, &ibpkey) < 0)
229			goto err;
230
231		/* Invoke handler */
232		status = fn(ibpkey, arg);
233		if (status < 0)
234			goto err;
235
236		sepol_ibpkey_free(ibpkey);
237		ibpkey = NULL;
238
239		/* Handler requested exit */
240		if (status > 0)
241			break;
242	}
243
244	return STATUS_SUCCESS;
245
246err:
247	ERR(handle, "could not iterate over ibpkeys");
248	sepol_ibpkey_free(ibpkey);
249	return STATUS_ERR;
250}
251