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 
12 struct 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 
28 struct 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 
node_parse_addr(sepol_handle_t * handle,const char * addr_str,int proto,char * addr_bytes)44 static 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 
node_alloc_addr(sepol_handle_t * handle,int proto,char ** addr,size_t * addr_sz)92 static 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 
node_expand_addr(sepol_handle_t * handle,char * addr_bytes,int proto,char * addr_str)138 static 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 
node_alloc_addr_string(sepol_handle_t * handle,int proto,char ** addr)193 static 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 */
sepol_node_key_create(sepol_handle_t * handle,const char * addr,const char * mask,int proto,sepol_node_key_t ** key_ptr)232 int 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 
hidden_def(sepol_node_key_create)270 hidden_def(sepol_node_key_create)
271 
272 void 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 
hidden_def(sepol_node_key_unpack)281 hidden_def(sepol_node_key_unpack)
282 
283 int 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 
sepol_node_key_free(sepol_node_key_t * key)314 void 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 
hidden_def(sepol_node_key_free)325 hidden_def(sepol_node_key_free)
326 
327 int 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 
sepol_node_compare2(const sepol_node_t * node,const sepol_node_t * node2)345 int 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 */
sepol_node_get_addr(sepol_handle_t * handle,const sepol_node_t * node,char ** addr)365 int 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 
hidden_def(sepol_node_get_addr)386 hidden_def(sepol_node_get_addr)
387 
388 int 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 
hidden_def(sepol_node_get_addr_bytes)405 hidden_def(sepol_node_get_addr_bytes)
406 
407 int 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 
hidden_def(sepol_node_set_addr)431 hidden_def(sepol_node_set_addr)
432 
433 int 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 
hidden_def(sepol_node_set_addr_bytes)451 hidden_def(sepol_node_set_addr_bytes)
452 
453 /* Mask */
454 int 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 
hidden_def(sepol_node_get_mask)475 hidden_def(sepol_node_get_mask)
476 
477 int 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 
hidden_def(sepol_node_get_mask_bytes)494 hidden_def(sepol_node_get_mask_bytes)
495 
496 int 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 
hidden_def(sepol_node_set_mask)520 hidden_def(sepol_node_set_mask)
521 
522 int 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 
hidden_def(sepol_node_set_mask_bytes)539 hidden_def(sepol_node_set_mask_bytes)
540 
541 /* Protocol */
542 int sepol_node_get_proto(const sepol_node_t * node)
543 {
544 
545 	return node->proto;
546 }
547 
hidden_def(sepol_node_get_proto)548 hidden_def(sepol_node_get_proto)
549 
550 void sepol_node_set_proto(sepol_node_t * node, int proto)
551 {
552 
553 	node->proto = proto;
554 }
555 
hidden_def(sepol_node_set_proto)556 hidden_def(sepol_node_set_proto)
557 
558 const 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 
hidden_def(sepol_node_get_proto_str)571 hidden_def(sepol_node_get_proto_str)
572 
573 /* Create */
574 int 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 
hidden_def(sepol_node_create)595 hidden_def(sepol_node_create)
596 
597 /* Deep copy clone */
598 int 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 */
sepol_node_free(sepol_node_t * node)636 void 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 
hidden_def(sepol_node_free)648 hidden_def(sepol_node_free)
649 
650 /* Context */
651 sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
652 {
653 
654 	return node->con;
655 }
656 
hidden_def(sepol_node_get_con)657 hidden_def(sepol_node_get_con)
658 
659 int 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 
675 hidden_def(sepol_node_set_con)
676