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