1#include <stdlib.h>
2#include <stddef.h>
3#include <string.h>
4#include <netinet/in.h>
5#include <arpa/inet.h>
6#include <errno.h>
7
8#include "node_internal.h"
9#include "context_internal.h"
10#include "debug.h"
11
12struct sepol_node {
13
14	/* Network address and mask */
15	char *addr;
16	size_t addr_sz;
17
18	char *mask;
19	size_t mask_sz;
20
21	/* Protocol */
22	int proto;
23
24	/* Context */
25	sepol_context_t *con;
26};
27
28struct sepol_node_key {
29
30	/* Network address and mask */
31	char *addr;
32	size_t addr_sz;
33
34	char *mask;
35	size_t mask_sz;
36
37	/* Protocol */
38	int proto;
39};
40
41/* Converts a string represtation (addr_str)
42 * to a numeric representation (addr_bytes) */
43
44static int node_parse_addr(sepol_handle_t * handle,
45			   const char *addr_str, int proto, char *addr_bytes)
46{
47
48	switch (proto) {
49
50	case SEPOL_PROTO_IP4:
51		{
52			struct in_addr in_addr;
53
54			if (inet_pton(AF_INET, addr_str, &in_addr) <= 0) {
55				ERR(handle, "could not parse IPv4 address "
56				    "%s: %s", addr_str, strerror(errno));
57				return STATUS_ERR;
58			}
59
60			memcpy(addr_bytes, &in_addr.s_addr, 4);
61			break;
62		}
63	case SEPOL_PROTO_IP6:
64		{
65			struct in6_addr in_addr;
66
67			if (inet_pton(AF_INET6, addr_str, &in_addr) <= 0) {
68				ERR(handle, "could not parse IPv6 address "
69				    "%s: %s", addr_str, strerror(errno));
70				return STATUS_ERR;
71			}
72
73#ifdef DARWIN
74			memcpy(addr_bytes, in_addr.s6_addr, 16);
75#else
76			memcpy(addr_bytes, in_addr.s6_addr32, 16);
77#endif
78			break;
79		}
80	default:
81		ERR(handle, "unsupported protocol %u, could not "
82		    "parse address", proto);
83		return STATUS_ERR;
84	}
85
86	return STATUS_SUCCESS;
87}
88
89/* Allocates a sufficiently large buffer (addr, addr_sz)
90 * according the the protocol */
91
92static int node_alloc_addr(sepol_handle_t * handle,
93			   int proto, char **addr, size_t * addr_sz)
94{
95
96	char *tmp_addr = NULL;
97	size_t tmp_addr_sz;
98
99	switch (proto) {
100
101	case SEPOL_PROTO_IP4:
102		tmp_addr_sz = 4;
103		tmp_addr = malloc(4);
104		if (!tmp_addr)
105			goto omem;
106		break;
107
108	case SEPOL_PROTO_IP6:
109		tmp_addr_sz = 16;
110		tmp_addr = malloc(16);
111		if (!tmp_addr)
112			goto omem;
113		break;
114
115	default:
116		ERR(handle, "unsupported protocol %u", proto);
117		goto err;
118	}
119
120	*addr = tmp_addr;
121	*addr_sz = tmp_addr_sz;
122	return STATUS_SUCCESS;
123
124      omem:
125	ERR(handle, "out of memory");
126
127      err:
128	free(tmp_addr);
129	ERR(handle, "could not allocate address of protocol %s",
130	    sepol_node_get_proto_str(proto));
131	return STATUS_ERR;
132}
133
134/* Converts a numeric representation (addr_bytes)
135 * to a string representation (addr_str), according to
136 * the protocol */
137
138static int node_expand_addr(sepol_handle_t * handle,
139			    char *addr_bytes, int proto, char *addr_str)
140{
141
142	switch (proto) {
143
144	case SEPOL_PROTO_IP4:
145		{
146			struct in_addr addr;
147			memset(&addr, 0, sizeof(struct in_addr));
148			memcpy(&addr.s_addr, addr_bytes, 4);
149
150			if (inet_ntop(AF_INET, &addr, addr_str,
151				      INET_ADDRSTRLEN) == NULL) {
152
153				ERR(handle,
154				    "could not expand IPv4 address to string: %s",
155				    strerror(errno));
156				return STATUS_ERR;
157			}
158			break;
159		}
160
161	case SEPOL_PROTO_IP6:
162		{
163			struct in6_addr addr;
164			memset(&addr, 0, sizeof(struct in6_addr));
165#ifdef DARWIN
166			memcpy(&addr.s6_addr[0], addr_bytes, 16);
167#else
168			memcpy(&addr.s6_addr32[0], addr_bytes, 16);
169#endif
170			if (inet_ntop(AF_INET6, &addr, addr_str,
171				      INET6_ADDRSTRLEN) == NULL) {
172
173				ERR(handle,
174				    "could not expand IPv6 address to string: %s",
175				    strerror(errno));
176				return STATUS_ERR;
177			}
178			break;
179		}
180
181	default:
182		ERR(handle, "unsupported protocol %u, could not"
183		    " expand address to string", proto);
184		return STATUS_ERR;
185	}
186
187	return STATUS_SUCCESS;
188}
189
190/* Allocates a sufficiently large address string (addr)
191 * according to the protocol */
192
193static int node_alloc_addr_string(sepol_handle_t * handle,
194				  int proto, char **addr)
195{
196
197	char *tmp_addr = NULL;
198
199	switch (proto) {
200
201	case SEPOL_PROTO_IP4:
202		tmp_addr = malloc(INET_ADDRSTRLEN);
203		if (!tmp_addr)
204			goto omem;
205		break;
206
207	case SEPOL_PROTO_IP6:
208		tmp_addr = malloc(INET6_ADDRSTRLEN);
209		if (!tmp_addr)
210			goto omem;
211		break;
212
213	default:
214		ERR(handle, "unsupported protocol %u", proto);
215		goto err;
216	}
217
218	*addr = tmp_addr;
219	return STATUS_SUCCESS;
220
221      omem:
222	ERR(handle, "out of memory");
223
224      err:
225	free(tmp_addr);
226	ERR(handle, "could not allocate string buffer for "
227	    "address of protocol %s", sepol_node_get_proto_str(proto));
228	return STATUS_ERR;
229}
230
231/* Key */
232int sepol_node_key_create(sepol_handle_t * handle,
233			  const char *addr,
234			  const char *mask,
235			  int proto, sepol_node_key_t ** key_ptr)
236{
237
238	sepol_node_key_t *tmp_key =
239	    (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
240	if (!tmp_key)
241		goto omem;
242
243	if (node_alloc_addr(handle, proto, &tmp_key->addr, &tmp_key->addr_sz) <
244	    0)
245		goto err;
246	if (node_parse_addr(handle, addr, proto, tmp_key->addr) < 0)
247		goto err;
248
249	if (node_alloc_addr(handle, proto, &tmp_key->mask, &tmp_key->mask_sz) <
250	    0)
251		goto err;
252	if (node_parse_addr(handle, mask, proto, tmp_key->mask) < 0)
253		goto err;
254
255	tmp_key->proto = proto;
256
257	*key_ptr = tmp_key;
258	return STATUS_SUCCESS;
259
260      omem:
261	ERR(handle, "out of memory");
262
263      err:
264	sepol_node_key_free(tmp_key);
265	ERR(handle, "could not create node key for (%s, %s, %s)",
266	    addr, mask, sepol_node_get_proto_str(proto));
267	return STATUS_ERR;
268}
269
270hidden_def(sepol_node_key_create)
271
272void sepol_node_key_unpack(const sepol_node_key_t * key,
273			   const char **addr, const char **mask, int *proto)
274{
275
276	*addr = key->addr;
277	*mask = key->mask;
278	*proto = key->proto;
279}
280
281hidden_def(sepol_node_key_unpack)
282
283int sepol_node_key_extract(sepol_handle_t * handle,
284			   const sepol_node_t * node,
285			   sepol_node_key_t ** key_ptr)
286{
287
288	sepol_node_key_t *tmp_key =
289	    (sepol_node_key_t *) calloc(1, sizeof(sepol_node_key_t));
290	if (!tmp_key)
291		goto omem;
292
293	tmp_key->addr = malloc(node->addr_sz);
294	tmp_key->mask = malloc(node->mask_sz);
295
296	if (!tmp_key->addr || !tmp_key->mask)
297		goto omem;
298
299	memcpy(tmp_key->addr, node->addr, node->addr_sz);
300	memcpy(tmp_key->mask, node->mask, node->mask_sz);
301	tmp_key->addr_sz = node->addr_sz;
302	tmp_key->mask_sz = node->mask_sz;
303	tmp_key->proto = node->proto;
304
305	*key_ptr = tmp_key;
306	return STATUS_SUCCESS;
307
308      omem:
309	sepol_node_key_free(tmp_key);
310	ERR(handle, "out of memory, could not extract node key");
311	return STATUS_ERR;
312}
313
314void sepol_node_key_free(sepol_node_key_t * key)
315{
316
317	if (!key)
318		return;
319
320	free(key->addr);
321	free(key->mask);
322	free(key);
323}
324
325hidden_def(sepol_node_key_free)
326
327int sepol_node_compare(const sepol_node_t * node, const sepol_node_key_t * key)
328{
329
330	int rc1, rc2;
331
332	if ((node->addr_sz < key->addr_sz) || (node->mask_sz < key->mask_sz))
333		return -1;
334
335	else if ((node->addr_sz > key->addr_sz) ||
336		 (node->mask_sz > key->mask_sz))
337		return 1;
338
339	rc1 = memcmp(node->addr, key->addr, node->addr_sz);
340	rc2 = memcmp(node->mask, key->mask, node->mask_sz);
341
342	return (rc2 != 0) ? rc2 : rc1;
343}
344
345int sepol_node_compare2(const sepol_node_t * node, const sepol_node_t * node2)
346{
347
348	int rc1, rc2;
349
350	if ((node->addr_sz < node2->addr_sz) ||
351	    (node->mask_sz < node2->mask_sz))
352		return -1;
353
354	else if ((node->addr_sz > node2->addr_sz) ||
355		 (node->mask_sz > node2->mask_sz))
356		return 1;
357
358	rc1 = memcmp(node->addr, node2->addr, node->addr_sz);
359	rc2 = memcmp(node->mask, node2->mask, node->mask_sz);
360
361	return (rc2 != 0) ? rc2 : rc1;
362}
363
364/* Addr */
365int sepol_node_get_addr(sepol_handle_t * handle,
366			const sepol_node_t * node, char **addr)
367{
368
369	char *tmp_addr = NULL;
370
371	if (node_alloc_addr_string(handle, node->proto, &tmp_addr) < 0)
372		goto err;
373
374	if (node_expand_addr(handle, node->addr, node->proto, tmp_addr) < 0)
375		goto err;
376
377	*addr = tmp_addr;
378	return STATUS_SUCCESS;
379
380      err:
381	free(tmp_addr);
382	ERR(handle, "could not get node address");
383	return STATUS_ERR;
384}
385
386hidden_def(sepol_node_get_addr)
387
388int sepol_node_get_addr_bytes(sepol_handle_t * handle,
389			      const sepol_node_t * node,
390			      char **buffer, size_t * bsize)
391{
392
393	char *tmp_buf = malloc(node->addr_sz);
394	if (!tmp_buf) {
395		ERR(handle, "out of memory, could not get address bytes");
396		return STATUS_ERR;
397	}
398
399	memcpy(tmp_buf, node->addr, node->addr_sz);
400	*buffer = tmp_buf;
401	*bsize = node->addr_sz;
402	return STATUS_SUCCESS;
403}
404
405hidden_def(sepol_node_get_addr_bytes)
406
407int sepol_node_set_addr(sepol_handle_t * handle,
408			sepol_node_t * node, int proto, const char *addr)
409{
410
411	char *tmp_addr = NULL;
412	size_t tmp_addr_sz;
413
414	if (node_alloc_addr(handle, proto, &tmp_addr, &tmp_addr_sz) < 0)
415		goto err;
416
417	if (node_parse_addr(handle, addr, proto, tmp_addr) < 0)
418		goto err;
419
420	free(node->addr);
421	node->addr = tmp_addr;
422	node->addr_sz = tmp_addr_sz;
423	return STATUS_SUCCESS;
424
425      err:
426	free(tmp_addr);
427	ERR(handle, "could not set node address to %s", addr);
428	return STATUS_ERR;
429}
430
431hidden_def(sepol_node_set_addr)
432
433int sepol_node_set_addr_bytes(sepol_handle_t * handle,
434			      sepol_node_t * node,
435			      const char *addr, size_t addr_sz)
436{
437
438	char *tmp_addr = malloc(addr_sz);
439	if (!tmp_addr) {
440		ERR(handle, "out of memory, could not " "set node address");
441		return STATUS_ERR;
442	}
443
444	memcpy(tmp_addr, addr, addr_sz);
445	free(node->addr);
446	node->addr = tmp_addr;
447	node->addr_sz = addr_sz;
448	return STATUS_SUCCESS;
449}
450
451hidden_def(sepol_node_set_addr_bytes)
452
453/* Mask */
454int sepol_node_get_mask(sepol_handle_t * handle,
455			const sepol_node_t * node, char **mask)
456{
457
458	char *tmp_mask = NULL;
459
460	if (node_alloc_addr_string(handle, node->proto, &tmp_mask) < 0)
461		goto err;
462
463	if (node_expand_addr(handle, node->mask, node->proto, tmp_mask) < 0)
464		goto err;
465
466	*mask = tmp_mask;
467	return STATUS_SUCCESS;
468
469      err:
470	free(tmp_mask);
471	ERR(handle, "could not get node netmask");
472	return STATUS_ERR;
473}
474
475hidden_def(sepol_node_get_mask)
476
477int sepol_node_get_mask_bytes(sepol_handle_t * handle,
478			      const sepol_node_t * node,
479			      char **buffer, size_t * bsize)
480{
481
482	char *tmp_buf = malloc(node->mask_sz);
483	if (!tmp_buf) {
484		ERR(handle, "out of memory, could not get netmask bytes");
485		return STATUS_ERR;
486	}
487
488	memcpy(tmp_buf, node->mask, node->mask_sz);
489	*buffer = tmp_buf;
490	*bsize = node->mask_sz;
491	return STATUS_SUCCESS;
492}
493
494hidden_def(sepol_node_get_mask_bytes)
495
496int sepol_node_set_mask(sepol_handle_t * handle,
497			sepol_node_t * node, int proto, const char *mask)
498{
499
500	char *tmp_mask = NULL;
501	size_t tmp_mask_sz;
502
503	if (node_alloc_addr(handle, proto, &tmp_mask, &tmp_mask_sz) < 0)
504		goto err;
505
506	if (node_parse_addr(handle, mask, proto, tmp_mask) < 0)
507		goto err;
508
509	free(node->mask);
510	node->mask = tmp_mask;
511	node->mask_sz = tmp_mask_sz;
512	return STATUS_SUCCESS;
513
514      err:
515	free(tmp_mask);
516	ERR(handle, "could not set node netmask to %s", mask);
517	return STATUS_ERR;
518}
519
520hidden_def(sepol_node_set_mask)
521
522int sepol_node_set_mask_bytes(sepol_handle_t * handle,
523			      sepol_node_t * node,
524			      const char *mask, size_t mask_sz)
525{
526
527	char *tmp_mask = malloc(mask_sz);
528	if (!tmp_mask) {
529		ERR(handle, "out of memory, could not " "set node netmask");
530		return STATUS_ERR;
531	}
532	memcpy(tmp_mask, mask, mask_sz);
533	free(node->mask);
534	node->mask = tmp_mask;
535	node->mask_sz = mask_sz;
536	return STATUS_SUCCESS;
537}
538
539hidden_def(sepol_node_set_mask_bytes)
540
541/* Protocol */
542int sepol_node_get_proto(const sepol_node_t * node)
543{
544
545	return node->proto;
546}
547
548hidden_def(sepol_node_get_proto)
549
550void sepol_node_set_proto(sepol_node_t * node, int proto)
551{
552
553	node->proto = proto;
554}
555
556hidden_def(sepol_node_set_proto)
557
558const char *sepol_node_get_proto_str(int proto)
559{
560
561	switch (proto) {
562	case SEPOL_PROTO_IP4:
563		return "ipv4";
564	case SEPOL_PROTO_IP6:
565		return "ipv6";
566	default:
567		return "???";
568	}
569}
570
571hidden_def(sepol_node_get_proto_str)
572
573/* Create */
574int sepol_node_create(sepol_handle_t * handle, sepol_node_t ** node)
575{
576
577	sepol_node_t *tmp_node = (sepol_node_t *) malloc(sizeof(sepol_node_t));
578
579	if (!tmp_node) {
580		ERR(handle, "out of memory, could not create " "node record");
581		return STATUS_ERR;
582	}
583
584	tmp_node->addr = NULL;
585	tmp_node->addr_sz = 0;
586	tmp_node->mask = NULL;
587	tmp_node->mask_sz = 0;
588	tmp_node->proto = SEPOL_PROTO_IP4;
589	tmp_node->con = NULL;
590	*node = tmp_node;
591
592	return STATUS_SUCCESS;
593}
594
595hidden_def(sepol_node_create)
596
597/* Deep copy clone */
598int sepol_node_clone(sepol_handle_t * handle,
599		     const sepol_node_t * node, sepol_node_t ** node_ptr)
600{
601
602	sepol_node_t *new_node = NULL;
603	if (sepol_node_create(handle, &new_node) < 0)
604		goto err;
605
606	/* Copy address, mask, protocol */
607	new_node->addr = malloc(node->addr_sz);
608	new_node->mask = malloc(node->mask_sz);
609	if (!new_node->addr || !new_node->mask)
610		goto omem;
611
612	memcpy(new_node->addr, node->addr, node->addr_sz);
613	memcpy(new_node->mask, node->mask, node->mask_sz);
614	new_node->addr_sz = node->addr_sz;
615	new_node->mask_sz = node->mask_sz;
616	new_node->proto = node->proto;
617
618	/* Copy context */
619	if (node->con &&
620	    (sepol_context_clone(handle, node->con, &new_node->con) < 0))
621		goto err;
622
623	*node_ptr = new_node;
624	return STATUS_SUCCESS;
625
626      omem:
627	ERR(handle, "out of memory");
628
629      err:
630	ERR(handle, "could not clone node record");
631	sepol_node_free(new_node);
632	return STATUS_ERR;
633}
634
635/* Destroy */
636void sepol_node_free(sepol_node_t * node)
637{
638
639	if (!node)
640		return;
641
642	sepol_context_free(node->con);
643	free(node->addr);
644	free(node->mask);
645	free(node);
646}
647
648hidden_def(sepol_node_free)
649
650/* Context */
651sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
652{
653
654	return node->con;
655}
656
657hidden_def(sepol_node_get_con)
658
659int sepol_node_set_con(sepol_handle_t * handle,
660		       sepol_node_t * node, sepol_context_t * con)
661{
662
663	sepol_context_t *newcon;
664
665	if (sepol_context_clone(handle, con, &newcon) < 0) {
666		ERR(handle, "out of memory, could not set node context");
667		return STATUS_ERR;
668	}
669
670	sepol_context_free(node->con);
671	node->con = newcon;
672	return STATUS_SUCCESS;
673}
674
675hidden_def(sepol_node_set_con)
676