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