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