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