1#include <stdlib.h>
2#include <string.h>
3#include <netinet/in.h>
4#include <arpa/inet.h>
5#include <errno.h>
6#include <sepol/ibpkey_record.h>
7
8#include "ibpkey_internal.h"
9#include "context_internal.h"
10#include "debug.h"
11
12struct sepol_ibpkey {
13	/* Subnet prefix */
14	uint64_t subnet_prefix;
15
16	/* Low - High range. Same for single ibpkeys. */
17	int low, high;
18
19	/* Context */
20	sepol_context_t *con;
21};
22
23struct sepol_ibpkey_key {
24	/* Subnet prefix */
25	uint64_t subnet_prefix;
26
27	/* Low - High range. Same for single ibpkeys. */
28	int low, high;
29};
30
31/* Converts a string represtation (subnet_prefix_str)
32 * to a numeric representation (subnet_prefix_bytes)
33 */
34static int ibpkey_parse_subnet_prefix(sepol_handle_t *handle,
35				      const char *subnet_prefix_str,
36				      uint64_t *subnet_prefix)
37{
38	struct in6_addr in_addr;
39
40	if (inet_pton(AF_INET6, subnet_prefix_str, &in_addr) <= 0) {
41		ERR(handle, "could not parse IPv6 address for ibpkey subnet prefix %s: %s",
42		    subnet_prefix_str, strerror(errno));
43		return STATUS_ERR;
44	}
45
46	memcpy(subnet_prefix, in_addr.s6_addr, sizeof(*subnet_prefix));
47
48	return STATUS_SUCCESS;
49}
50
51/* Converts a numeric representation (subnet_prefix_bytes)
52 * to a string representation (subnet_prefix_str)
53 */
54
55static int ibpkey_expand_subnet_prefix(sepol_handle_t *handle,
56				       uint64_t subnet_prefix,
57				       char *subnet_prefix_str)
58{
59	struct in6_addr addr;
60
61	memset(&addr, 0, sizeof(struct in6_addr));
62	memcpy(&addr.s6_addr[0], &subnet_prefix, sizeof(subnet_prefix));
63
64	if (inet_ntop(AF_INET6, &addr, subnet_prefix_str,
65		      INET6_ADDRSTRLEN) == NULL) {
66		ERR(handle,
67		    "could not expand IPv6 address to string: %s",
68		    strerror(errno));
69		return STATUS_ERR;
70	}
71
72	return STATUS_SUCCESS;
73}
74
75/* Allocates a sufficiently large string (subnet_prefix)
76 * for an IPV6 address for the subnet prefix
77 */
78static int ibpkey_alloc_subnet_prefix_string(sepol_handle_t *handle,
79					     char **subnet_prefix)
80{
81	char *tmp_subnet_prefix = NULL;
82
83	tmp_subnet_prefix = malloc(INET6_ADDRSTRLEN);
84
85	if (!tmp_subnet_prefix)
86		goto omem;
87
88	*subnet_prefix = tmp_subnet_prefix;
89	return STATUS_SUCCESS;
90
91omem:
92	ERR(handle, "out of memory");
93
94	ERR(handle, "could not allocate string buffer for subnet_prefix");
95	return STATUS_ERR;
96}
97
98/* Key */
99int sepol_ibpkey_key_create(sepol_handle_t *handle,
100			    const char *subnet_prefix,
101			    int low, int high,
102			    sepol_ibpkey_key_t **key_ptr)
103{
104	sepol_ibpkey_key_t *tmp_key =
105	    (sepol_ibpkey_key_t *)malloc(sizeof(sepol_ibpkey_key_t));
106
107	if (!tmp_key) {
108		ERR(handle, "out of memory, could not create ibpkey key");
109		goto omem;
110	}
111
112	if (ibpkey_parse_subnet_prefix(handle, subnet_prefix, &tmp_key->subnet_prefix) < 0)
113		goto err;
114
115	tmp_key->low = low;
116	tmp_key->high = high;
117
118	*key_ptr = tmp_key;
119	return STATUS_SUCCESS;
120
121omem:
122	ERR(handle, "out of memory");
123
124err:
125	sepol_ibpkey_key_free(tmp_key);
126	ERR(handle, "could not create ibpkey key for subnet prefix%s, range %u, %u",
127	    subnet_prefix, low, high);
128	return STATUS_ERR;
129}
130
131hidden_def(sepol_ibpkey_key_create)
132
133void sepol_ibpkey_key_unpack(const sepol_ibpkey_key_t *key,
134			     uint64_t *subnet_prefix, int *low, int *high)
135{
136	*subnet_prefix = key->subnet_prefix;
137	*low = key->low;
138	*high = key->high;
139}
140
141hidden_def(sepol_ibpkey_key_unpack)
142
143int sepol_ibpkey_key_extract(sepol_handle_t *handle,
144			     const sepol_ibpkey_t *ibpkey,
145			     sepol_ibpkey_key_t **key_ptr)
146{
147	char subnet_prefix_str[INET6_ADDRSTRLEN];
148
149	ibpkey_expand_subnet_prefix(handle, ibpkey->subnet_prefix, subnet_prefix_str);
150
151	if (sepol_ibpkey_key_create
152	    (handle, subnet_prefix_str, ibpkey->low, ibpkey->high, key_ptr) < 0) {
153		ERR(handle, "could not extract key from ibpkey %s %d:%d",
154		    subnet_prefix_str,
155		    ibpkey->low, ibpkey->high);
156
157		return STATUS_ERR;
158	}
159
160	return STATUS_SUCCESS;
161}
162
163void sepol_ibpkey_key_free(sepol_ibpkey_key_t *key)
164{
165	if (!key)
166		return;
167	free(key);
168}
169
170int sepol_ibpkey_compare(const sepol_ibpkey_t *ibpkey, const sepol_ibpkey_key_t *key)
171{
172	if (ibpkey->subnet_prefix < key->subnet_prefix)
173		return -1;
174	if (key->subnet_prefix < ibpkey->subnet_prefix)
175		return 1;
176
177	if (ibpkey->low < key->low)
178		return -1;
179	if (key->low < ibpkey->low)
180		return 1;
181
182	if (ibpkey->high < key->high)
183		return -1;
184	if (key->high < ibpkey->high)
185		return 1;
186
187	return 0;
188}
189
190int sepol_ibpkey_compare2(const sepol_ibpkey_t *ibpkey, const sepol_ibpkey_t *ibpkey2)
191{
192	if (ibpkey->subnet_prefix < ibpkey2->subnet_prefix)
193		return -1;
194	if (ibpkey2->subnet_prefix < ibpkey->subnet_prefix)
195		return 1;
196
197	if (ibpkey->low < ibpkey2->low)
198		return -1;
199	if (ibpkey2->low < ibpkey->low)
200		return 1;
201
202	if (ibpkey->high < ibpkey2->high)
203		return -1;
204	if (ibpkey2->high < ibpkey->high)
205		return 1;
206
207	return 0;
208}
209
210/* Pkey */
211int sepol_ibpkey_get_low(const sepol_ibpkey_t *ibpkey)
212{
213	return ibpkey->low;
214}
215
216hidden_def(sepol_ibpkey_get_low)
217
218int sepol_ibpkey_get_high(const sepol_ibpkey_t *ibpkey)
219{
220	return ibpkey->high;
221}
222
223hidden_def(sepol_ibpkey_get_high)
224
225void sepol_ibpkey_set_pkey(sepol_ibpkey_t *ibpkey, int pkey_num)
226{
227	ibpkey->low = pkey_num;
228	ibpkey->high = pkey_num;
229}
230
231void sepol_ibpkey_set_range(sepol_ibpkey_t *ibpkey, int low, int high)
232{
233	ibpkey->low = low;
234	ibpkey->high = high;
235}
236
237hidden_def(sepol_ibpkey_set_range)
238
239int sepol_ibpkey_get_subnet_prefix(sepol_handle_t *handle,
240				   const sepol_ibpkey_t *ibpkey,
241				   char **subnet_prefix)
242{
243	char *tmp_subnet_prefix = NULL;
244
245	if (ibpkey_alloc_subnet_prefix_string(handle, &tmp_subnet_prefix) < 0)
246		goto err;
247
248	if (ibpkey_expand_subnet_prefix(handle, ibpkey->subnet_prefix, tmp_subnet_prefix) < 0)
249		goto err;
250
251	*subnet_prefix = tmp_subnet_prefix;
252	return STATUS_SUCCESS;
253
254err:
255	free(tmp_subnet_prefix);
256	ERR(handle, "could not get ibpkey subnet_prefix");
257	return STATUS_ERR;
258}
259
260hidden_def(sepol_ibpkey_get_subnet_prefix)
261
262/* Subnet prefix */
263uint64_t sepol_ibpkey_get_subnet_prefix_bytes(const sepol_ibpkey_t *ibpkey)
264{
265	return ibpkey->subnet_prefix;
266}
267
268hidden_def(sepol_ibpkey_get_subnet_prefix_bytes)
269
270int sepol_ibpkey_set_subnet_prefix(sepol_handle_t *handle,
271				   sepol_ibpkey_t *ibpkey,
272				   const char *subnet_prefix_str)
273{
274	uint64_t tmp = 0;
275
276	if (ibpkey_parse_subnet_prefix(handle, subnet_prefix_str, &tmp) < 0)
277		goto err;
278
279	ibpkey->subnet_prefix = tmp;
280	return STATUS_SUCCESS;
281
282err:
283	ERR(handle, "could not set ibpkey subnet prefix to %s", subnet_prefix_str);
284	return STATUS_ERR;
285}
286
287hidden_def(sepol_ibpkey_set_subnet_prefix)
288
289void sepol_ibpkey_set_subnet_prefix_bytes(sepol_ibpkey_t *ibpkey,
290					  uint64_t subnet_prefix)
291{
292	ibpkey->subnet_prefix = subnet_prefix;
293}
294
295hidden_def(sepol_ibpkey_set_subnet_prefix_bytes)
296
297/* Create */
298int sepol_ibpkey_create(sepol_handle_t *handle, sepol_ibpkey_t **ibpkey)
299{
300	sepol_ibpkey_t *tmp_ibpkey = (sepol_ibpkey_t *)malloc(sizeof(sepol_ibpkey_t));
301
302	if (!tmp_ibpkey) {
303		ERR(handle, "out of memory, could not create ibpkey record");
304		return STATUS_ERR;
305	}
306
307	tmp_ibpkey->subnet_prefix = 0;
308	tmp_ibpkey->low = 0;
309	tmp_ibpkey->high = 0;
310	tmp_ibpkey->con = NULL;
311	*ibpkey = tmp_ibpkey;
312
313	return STATUS_SUCCESS;
314}
315
316hidden_def(sepol_ibpkey_create)
317
318/* Deep copy clone */
319int sepol_ibpkey_clone(sepol_handle_t *handle,
320		       const sepol_ibpkey_t *ibpkey, sepol_ibpkey_t **ibpkey_ptr)
321{
322	sepol_ibpkey_t *new_ibpkey = NULL;
323
324	if (sepol_ibpkey_create(handle, &new_ibpkey) < 0)
325		goto err;
326
327	new_ibpkey->subnet_prefix = ibpkey->subnet_prefix;
328	new_ibpkey->low = ibpkey->low;
329	new_ibpkey->high = ibpkey->high;
330
331	if (ibpkey->con &&
332	    (sepol_context_clone(handle, ibpkey->con, &new_ibpkey->con) < 0))
333		goto err;
334
335	*ibpkey_ptr = new_ibpkey;
336	return STATUS_SUCCESS;
337
338err:
339	ERR(handle, "could not clone ibpkey record");
340	sepol_ibpkey_free(new_ibpkey);
341	return STATUS_ERR;
342}
343
344/* Destroy */
345void sepol_ibpkey_free(sepol_ibpkey_t *ibpkey)
346{
347	if (!ibpkey)
348		return;
349
350	sepol_context_free(ibpkey->con);
351	free(ibpkey);
352}
353
354hidden_def(sepol_ibpkey_free)
355
356/* Context */
357sepol_context_t *sepol_ibpkey_get_con(const sepol_ibpkey_t *ibpkey)
358{
359	return ibpkey->con;
360}
361
362hidden_def(sepol_ibpkey_get_con)
363
364int sepol_ibpkey_set_con(sepol_handle_t *handle,
365			 sepol_ibpkey_t *ibpkey, sepol_context_t *con)
366{
367	sepol_context_t *newcon;
368
369	if (sepol_context_clone(handle, con, &newcon) < 0) {
370		ERR(handle, "out of memory, could not set ibpkey context");
371		return STATUS_ERR;
372	}
373
374	sepol_context_free(ibpkey->con);
375	ibpkey->con = newcon;
376	return STATUS_SUCCESS;
377}
378
379hidden_def(sepol_ibpkey_set_con)
380