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 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
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: %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
node_alloc_addr_string(sepol_handle_t * handle,int proto,char ** addr)185 static 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 */
sepol_node_key_create(sepol_handle_t * handle,const char * addr,const char * mask,int proto,sepol_node_key_t ** key_ptr)224 int 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
hidden_def(sepol_node_key_create)262 hidden_def(sepol_node_key_create)
263
264 void 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
hidden_def(sepol_node_key_unpack)273 hidden_def(sepol_node_key_unpack)
274
275 int 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
sepol_node_key_free(sepol_node_key_t * key)306 void 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
hidden_def(sepol_node_key_free)317 hidden_def(sepol_node_key_free)
318
319 int 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
sepol_node_compare2(const sepol_node_t * node,const sepol_node_t * node2)337 int 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 */
sepol_node_get_addr(sepol_handle_t * handle,const sepol_node_t * node,char ** addr)357 int 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
hidden_def(sepol_node_get_addr)378 hidden_def(sepol_node_get_addr)
379
380 int 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
hidden_def(sepol_node_get_addr_bytes)397 hidden_def(sepol_node_get_addr_bytes)
398
399 int 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
hidden_def(sepol_node_set_addr)423 hidden_def(sepol_node_set_addr)
424
425 int 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
hidden_def(sepol_node_set_addr_bytes)443 hidden_def(sepol_node_set_addr_bytes)
444
445 /* Mask */
446 int 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
hidden_def(sepol_node_get_mask)467 hidden_def(sepol_node_get_mask)
468
469 int 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
hidden_def(sepol_node_get_mask_bytes)486 hidden_def(sepol_node_get_mask_bytes)
487
488 int 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
hidden_def(sepol_node_set_mask)512 hidden_def(sepol_node_set_mask)
513
514 int 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
hidden_def(sepol_node_set_mask_bytes)531 hidden_def(sepol_node_set_mask_bytes)
532
533 /* Protocol */
534 int sepol_node_get_proto(const sepol_node_t * node)
535 {
536
537 return node->proto;
538 }
539
hidden_def(sepol_node_get_proto)540 hidden_def(sepol_node_get_proto)
541
542 void sepol_node_set_proto(sepol_node_t * node, int proto)
543 {
544
545 node->proto = proto;
546 }
547
hidden_def(sepol_node_set_proto)548 hidden_def(sepol_node_set_proto)
549
550 const 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
hidden_def(sepol_node_get_proto_str)563 hidden_def(sepol_node_get_proto_str)
564
565 /* Create */
566 int 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
hidden_def(sepol_node_create)587 hidden_def(sepol_node_create)
588
589 /* Deep copy clone */
590 int 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 */
sepol_node_free(sepol_node_t * node)628 void 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
hidden_def(sepol_node_free)640 hidden_def(sepol_node_free)
641
642 /* Context */
643 sepol_context_t *sepol_node_get_con(const sepol_node_t * node)
644 {
645
646 return node->con;
647 }
648
hidden_def(sepol_node_get_con)649 hidden_def(sepol_node_get_con)
650
651 int 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
667 hidden_def(sepol_node_set_con)
668