]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
confile_utils: fix a signed integer overflow
[mirror_lxc.git] / src / lxc / confile_utils.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #include <arpa/inet.h>
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "conf.h"
13 #include "config.h"
14 #include "confile.h"
15 #include "confile_utils.h"
16 #include "error.h"
17 #include "list.h"
18 #include "lxc.h"
19 #include "log.h"
20 #include "lxccontainer.h"
21 #include "macro.h"
22 #include "memory_utils.h"
23 #include "network.h"
24 #include "parse.h"
25 #include "utils.h"
26
27 #ifndef HAVE_STRLCPY
28 #include "include/strlcpy.h"
29 #endif
30
31 lxc_log_define(confile_utils, lxc);
32
33 int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
34 unsigned long *hostid, unsigned long *range)
35 {
36 __do_free char *dup = NULL;
37 int ret = -1;
38 unsigned long tmp_hostid, tmp_nsid, tmp_range;
39 char tmp_type;
40 char *window, *slide;
41
42 /* Duplicate string. */
43 dup = strdup(idmap);
44 if (!dup)
45 return ret_errno(ENOMEM);
46
47 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
48
49 /* align */
50 slide = window = dup;
51 /* skip whitespace */
52 slide += strspn(slide, " \t\r");
53 if (slide != window && *slide == '\0')
54 return ret_errno(EINVAL);
55
56 /* Validate type. */
57 if (*slide != 'u' && *slide != 'g')
58 return log_error_errno(-EINVAL, EINVAL, "Invalid id mapping type: %c", *slide);
59
60 /* Assign type. */
61 tmp_type = *slide;
62
63 /* move beyond type */
64 slide++;
65 /* align */
66 window = slide;
67 /* Validate that only whitespace follows. */
68 slide += strspn(slide, " \t\r");
69 /* There must be whitespace. */
70 if (slide == window)
71 return ret_errno(EINVAL);
72
73 /* Mark beginning of nsid. */
74 window = slide;
75 /* Validate that non-whitespace follows. */
76 slide += strcspn(slide, " \t\r");
77 /* There must be non-whitespace. */
78 if (slide == window || *slide == '\0')
79 return ret_errno(EINVAL);
80 /* Mark end of nsid. */
81 *slide = '\0';
82
83 /* Parse nsid. */
84 ret = lxc_safe_ulong(window, &tmp_nsid);
85 if (ret < 0)
86 return log_error_errno(ret, errno, "Failed to parse nsid: %s", window);
87
88 /* Move beyond \0. */
89 slide++;
90 /* Validate that only whitespace follows. */
91 slide += strspn(slide, " \t\r");
92 /* If there was only one whitespace then we whiped it with our \0 above.
93 * So only ensure that we're not at the end of the string.
94 */
95 if (*slide == '\0')
96 return ret_errno(EINVAL);
97
98 /* Mark beginning of hostid. */
99 window = slide;
100 /* Validate that non-whitespace follows. */
101 slide += strcspn(slide, " \t\r");
102 /* There must be non-whitespace. */
103 if (slide == window || *slide == '\0')
104 return ret_errno(EINVAL);
105 /* Mark end of nsid. */
106 *slide = '\0';
107
108 /* Parse hostid. */
109 ret = lxc_safe_ulong(window, &tmp_hostid);
110 if (ret < 0)
111 return log_error_errno(ret, errno, "Failed to parse hostid: %s", window);
112
113 /* Move beyond \0. */
114 slide++;
115 /* Validate that only whitespace follows. */
116 slide += strspn(slide, " \t\r");
117 /* If there was only one whitespace then we whiped it with our \0 above.
118 * So only ensure that we're not at the end of the string.
119 */
120 if (*slide == '\0')
121 return ret_errno(EINVAL);
122
123 /* Mark beginning of range. */
124 window = slide;
125 /* Validate that non-whitespace follows. */
126 slide += strcspn(slide, " \t\r");
127 /* There must be non-whitespace. */
128 if (slide == window)
129 return ret_errno(EINVAL);
130
131 /* The range is the last valid entry we expect. So make sure that there
132 * is no trailing garbage and if there is, error out.
133 */
134 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
135 return ret_errno(EINVAL);
136
137 /* Mark end of range. */
138 *slide = '\0';
139
140 /* Parse range. */
141 ret = lxc_safe_ulong(window, &tmp_range);
142 if (ret < 0)
143 return log_error_errno(ret, errno, "Failed to parse id mapping range: %s", window);
144
145 *type = tmp_type;
146 *nsid = tmp_nsid;
147 *hostid = tmp_hostid;
148 *range = tmp_range;
149
150 /* Yay, we survived. */
151 return 0;
152 }
153
154 bool lxc_config_value_empty(const char *value)
155 {
156 if (value && strlen(value) > 0)
157 return false;
158
159 return true;
160 }
161
162 struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
163 {
164 __do_free struct lxc_list *newlist = NULL;
165 __do_free struct lxc_netdev *netdev = NULL;
166
167 /* network does not exist */
168 netdev = zalloc(sizeof(*netdev));
169 if (!netdev)
170 return ret_set_errno(NULL, ENOMEM);
171
172 lxc_list_init(&netdev->ipv4);
173 lxc_list_init(&netdev->ipv6);
174
175 /* give network a unique index */
176 netdev->idx = idx;
177
178 /* prepare new list */
179 newlist = lxc_list_new();
180 if (!newlist)
181 return ret_set_errno(NULL, ENOMEM);
182 newlist->elem = netdev;
183
184 if (tail)
185 lxc_list_add_tail(networks, newlist);
186 else
187 lxc_list_add(networks, newlist);
188 move_ptr(newlist);
189
190 return move_ptr(netdev);
191 }
192
193 /* Takes care of finding the correct netdev struct in the networks list or
194 * allocates a new one if it couldn't be found.
195 */
196 struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
197 unsigned int idx, bool allocate)
198 {
199 struct lxc_list *networks = &conf->network;
200 struct lxc_list *insert = networks;
201
202 /* lookup network */
203 if (!lxc_list_empty(networks)) {
204 lxc_list_for_each(insert, networks) {
205 struct lxc_netdev *netdev = insert->elem;
206
207 /* found network device */
208 if (netdev->idx == idx)
209 return netdev;
210
211 if (netdev->idx > idx)
212 break;
213 }
214 }
215
216 if (allocate)
217 return lxc_network_add(insert, idx, true);
218
219 return NULL;
220 }
221
222 void lxc_log_configured_netdevs(const struct lxc_conf *conf)
223 {
224 struct lxc_netdev *netdev;
225 struct lxc_list *it = (struct lxc_list *)&conf->network;;
226
227 if (!lxc_log_trace())
228 return;
229
230 if (lxc_list_empty(it)) {
231 TRACE("container has no networks configured");
232 return;
233 }
234
235 lxc_list_for_each(it, &conf->network) {
236 struct lxc_list *cur, *next;
237 struct lxc_inetdev *inet4dev;
238 struct lxc_inet6dev *inet6dev;
239 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
240
241 netdev = it->elem;
242
243 TRACE("index: %zd", netdev->idx);
244 TRACE("ifindex: %d", netdev->ifindex);
245
246 switch (netdev->type) {
247 case LXC_NET_VETH:
248 TRACE("type: veth");
249 TRACE("veth mode: %d", netdev->priv.veth_attr.mode);
250
251 if (netdev->priv.veth_attr.pair[0] != '\0')
252 TRACE("veth pair: %s",
253 netdev->priv.veth_attr.pair);
254
255 if (netdev->priv.veth_attr.veth1[0] != '\0')
256 TRACE("veth1 : %s",
257 netdev->priv.veth_attr.veth1);
258
259 if (netdev->priv.veth_attr.ifindex > 0)
260 TRACE("host side ifindex for veth device: %d",
261 netdev->priv.veth_attr.ifindex);
262
263 if (netdev->priv.veth_attr.vlan_id_set)
264 TRACE("veth vlan id: %d", netdev->priv.veth_attr.vlan_id);
265
266 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
267 unsigned short vlan_tagged_id = PTR_TO_USHORT(cur->elem);
268 TRACE("veth vlan tagged id: %u", vlan_tagged_id);
269 }
270
271 break;
272 case LXC_NET_MACVLAN:
273 TRACE("type: macvlan");
274
275 if (netdev->priv.macvlan_attr.mode > 0) {
276 char *mode;
277
278 mode = lxc_macvlan_flag_to_mode(
279 netdev->priv.macvlan_attr.mode);
280 TRACE("macvlan mode: %s",
281 mode ? mode : "(invalid mode)");
282 }
283 break;
284 case LXC_NET_IPVLAN:
285 TRACE("type: ipvlan");
286
287 char *mode;
288 mode = lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode);
289 TRACE("ipvlan mode: %s", mode ? mode : "(invalid mode)");
290
291 char *isolation;
292 isolation = lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation);
293 TRACE("ipvlan isolation: %s", isolation ? isolation : "(invalid isolation)");
294 break;
295 case LXC_NET_VLAN:
296 TRACE("type: vlan");
297 TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
298 break;
299 case LXC_NET_PHYS:
300 TRACE("type: phys");
301
302 if (netdev->priv.phys_attr.ifindex > 0)
303 TRACE("host side ifindex for phys device: %d",
304 netdev->priv.phys_attr.ifindex);
305 break;
306 case LXC_NET_EMPTY:
307 TRACE("type: empty");
308 break;
309 case LXC_NET_NONE:
310 TRACE("type: none");
311 break;
312 default:
313 ERROR("Invalid network type %d", netdev->type);
314 return;
315 }
316
317 if (netdev->type != LXC_NET_EMPTY) {
318 TRACE("flags: %s",
319 netdev->flags == IFF_UP ? "up" : "none");
320
321 if (netdev->link[0] != '\0')
322 TRACE("link: %s", netdev->link);
323
324 /* l2proxy only used when link is specified */
325 if (netdev->link[0] != '\0')
326 TRACE("l2proxy: %s", netdev->l2proxy ? "true" : "false");
327
328 if (netdev->name[0] != '\0')
329 TRACE("name: %s", netdev->name);
330
331 if (netdev->hwaddr)
332 TRACE("hwaddr: %s", netdev->hwaddr);
333
334 if (netdev->mtu)
335 TRACE("mtu: %s", netdev->mtu);
336
337 if (netdev->upscript)
338 TRACE("upscript: %s", netdev->upscript);
339
340 if (netdev->downscript)
341 TRACE("downscript: %s", netdev->downscript);
342
343 TRACE("ipv4 gateway auto: %s",
344 netdev->ipv4_gateway_auto ? "true" : "false");
345
346 TRACE("ipv4 gateway dev: %s",
347 netdev->ipv4_gateway_dev ? "true" : "false");
348
349 if (netdev->ipv4_gateway) {
350 inet_ntop(AF_INET, netdev->ipv4_gateway,
351 bufinet4, sizeof(bufinet4));
352 TRACE("ipv4 gateway: %s", bufinet4);
353 }
354
355 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
356 inet4dev = cur->elem;
357 inet_ntop(AF_INET, &inet4dev->addr, bufinet4,
358 sizeof(bufinet4));
359 TRACE("ipv4 addr: %s", bufinet4);
360 }
361
362 TRACE("ipv6 gateway auto: %s",
363 netdev->ipv6_gateway_auto ? "true" : "false");
364
365 TRACE("ipv6 gateway dev: %s",
366 netdev->ipv6_gateway_dev ? "true" : "false");
367
368 if (netdev->ipv6_gateway) {
369 inet_ntop(AF_INET6, netdev->ipv6_gateway,
370 bufinet6, sizeof(bufinet6));
371 TRACE("ipv6 gateway: %s", bufinet6);
372 }
373
374 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
375 inet6dev = cur->elem;
376 inet_ntop(AF_INET6, &inet6dev->addr, bufinet6,
377 sizeof(bufinet6));
378 TRACE("ipv6 addr: %s", bufinet6);
379 }
380
381 if (netdev->type == LXC_NET_VETH) {
382 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
383 inet4dev = cur->elem;
384 if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4))) {
385 ERROR("Invalid ipv4 veth route");
386 return;
387 }
388
389 TRACE("ipv4 veth route: %s/%u", bufinet4, inet4dev->prefix);
390 }
391
392 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
393 inet6dev = cur->elem;
394 if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6))) {
395 ERROR("Invalid ipv6 veth route");
396 return;
397 }
398
399 TRACE("ipv6 veth route: %s/%u", bufinet6, inet6dev->prefix);
400 }
401 }
402 }
403 }
404 }
405
406 static void lxc_free_netdev(struct lxc_netdev *netdev)
407 {
408 struct lxc_list *cur, *next;
409
410 if (!netdev)
411 return;
412
413 free(netdev->upscript);
414 free(netdev->downscript);
415 free(netdev->hwaddr);
416 free(netdev->mtu);
417
418 free(netdev->ipv4_gateway);
419 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
420 lxc_list_del(cur);
421 free(cur->elem);
422 free(cur);
423 }
424
425 free(netdev->ipv6_gateway);
426 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
427 lxc_list_del(cur);
428 free(cur->elem);
429 free(cur);
430 }
431
432 if (netdev->type == LXC_NET_VETH) {
433 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
434 lxc_list_del(cur);
435 free(cur->elem);
436 free(cur);
437 }
438
439 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
440 lxc_list_del(cur);
441 free(cur->elem);
442 free(cur);
443 }
444
445 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
446 lxc_list_del(cur);
447 free(cur);
448 }
449 }
450
451 free(netdev);
452 }
453
454 bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
455 {
456 struct lxc_list *cur, *next;
457
458 if (lxc_list_empty(&conf->network))
459 return false;
460
461 lxc_list_for_each_safe(cur, &conf->network, next) {
462 struct lxc_netdev *netdev = cur->elem;
463
464 if (netdev->idx != idx)
465 continue;
466
467 lxc_list_del(cur);
468 lxc_free_netdev(netdev);
469 free(cur);
470 return true;
471 }
472
473 return false;
474 }
475
476 void lxc_free_networks(struct lxc_list *networks)
477 {
478 struct lxc_list *cur, *next;
479
480 lxc_list_for_each_safe (cur, networks, next) {
481 struct lxc_netdev *netdev = cur->elem;
482
483 lxc_list_del(cur);
484 lxc_free_netdev(netdev);
485 free(cur);
486 }
487
488 /* prevent segfaults */
489 lxc_list_init(networks);
490 }
491
492 static struct lxc_veth_mode {
493 char *name;
494 int mode;
495 } veth_mode[] = {
496 { "bridge", VETH_MODE_BRIDGE },
497 { "router", VETH_MODE_ROUTER },
498 };
499
500 int lxc_veth_mode_to_flag(int *mode, const char *value)
501 {
502 for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
503 if (!strequal(veth_mode[i].name, value))
504 continue;
505
506 *mode = veth_mode[i].mode;
507 return 0;
508 }
509
510 return ret_errno(EINVAL);
511 }
512
513 char *lxc_veth_flag_to_mode(int mode)
514 {
515 for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
516 if (veth_mode[i].mode != mode)
517 continue;
518
519 return veth_mode[i].name;
520 }
521
522 return ret_set_errno(NULL, EINVAL);
523 }
524
525 static struct lxc_macvlan_mode {
526 char *name;
527 int mode;
528 } macvlan_mode[] = {
529 { "private", MACVLAN_MODE_PRIVATE },
530 { "vepa", MACVLAN_MODE_VEPA },
531 { "bridge", MACVLAN_MODE_BRIDGE },
532 { "passthru", MACVLAN_MODE_PASSTHRU },
533 };
534
535 int lxc_macvlan_mode_to_flag(int *mode, const char *value)
536 {
537 for (size_t i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
538 if (!strequal(macvlan_mode[i].name, value))
539 continue;
540
541 *mode = macvlan_mode[i].mode;
542 return 0;
543 }
544
545 return ret_errno(EINVAL);
546 }
547
548 char *lxc_macvlan_flag_to_mode(int mode)
549 {
550 for (size_t i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
551 if (macvlan_mode[i].mode != mode)
552 continue;
553
554 return macvlan_mode[i].name;
555 }
556
557 return ret_set_errno(NULL, EINVAL);
558 }
559
560 static struct lxc_ipvlan_mode {
561 char *name;
562 int mode;
563 } ipvlan_mode[] = {
564 { "l3", IPVLAN_MODE_L3 },
565 { "l3s", IPVLAN_MODE_L3S },
566 { "l2", IPVLAN_MODE_L2 },
567 };
568
569 int lxc_ipvlan_mode_to_flag(int *mode, const char *value)
570 {
571 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
572 if (!strequal(ipvlan_mode[i].name, value))
573 continue;
574
575 *mode = ipvlan_mode[i].mode;
576 return 0;
577 }
578
579 return ret_errno(EINVAL);
580 }
581
582 char *lxc_ipvlan_flag_to_mode(int mode)
583 {
584 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
585 if (ipvlan_mode[i].mode != mode)
586 continue;
587
588 return ipvlan_mode[i].name;
589 }
590
591 return ret_set_errno(NULL, EINVAL);
592 }
593
594 static struct lxc_ipvlan_isolation {
595 char *name;
596 int flag;
597 } ipvlan_isolation[] = {
598 { "bridge", IPVLAN_ISOLATION_BRIDGE },
599 { "private", IPVLAN_ISOLATION_PRIVATE },
600 { "vepa", IPVLAN_ISOLATION_VEPA },
601 };
602
603 int lxc_ipvlan_isolation_to_flag(int *flag, const char *value)
604 {
605 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
606 if (!strequal(ipvlan_isolation[i].name, value))
607 continue;
608
609 *flag = ipvlan_isolation[i].flag;
610 return 0;
611 }
612
613 return ret_errno(EINVAL);
614 }
615
616 char *lxc_ipvlan_flag_to_isolation(int flag)
617 {
618 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
619 if (ipvlan_isolation[i].flag != flag)
620 continue;
621
622 return ipvlan_isolation[i].name;
623 }
624
625 return ret_set_errno(NULL, EINVAL);
626 }
627
628 int set_config_string_item(char **conf_item, const char *value)
629 {
630 char *new_value;
631
632 if (lxc_config_value_empty(value)) {
633 free_disarm(*conf_item);
634 return 0;
635 }
636
637 new_value = strdup(value);
638 if (!new_value)
639 return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate string \"%s\"", value);
640
641 free_move_ptr(*conf_item, new_value);
642 return 0;
643 }
644
645 int set_config_string_item_max(char **conf_item, const char *value, size_t max)
646 {
647 if (strlen(value) >= max)
648 return log_error_errno(-ENAMETOOLONG, ENAMETOOLONG, "%s is too long (>= %lu)", value, (unsigned long)max);
649
650 return set_config_string_item(conf_item, value);
651 }
652
653 int set_config_path_item(char **conf_item, const char *value)
654 {
655 __do_free char *normalized = NULL;
656
657 normalized = lxc_deslashify(value);
658 if (!normalized)
659 return syserror_set(-ENOMEM, "Failed to normalize path config item");
660
661 return set_config_string_item_max(conf_item, normalized, PATH_MAX);
662 }
663
664 int set_config_bool_item(bool *conf_item, const char *value, bool empty_conf_action)
665 {
666 int ret;
667 unsigned int val = 0;
668
669 if (lxc_config_value_empty(value)) {
670 *conf_item = empty_conf_action;
671 return 0;
672 }
673
674 ret = lxc_safe_uint(value, &val);
675 if (ret < 0)
676 return ret;
677
678 switch (val) {
679 case 0:
680 *conf_item = false;
681 return 0;
682 case 1:
683 *conf_item = true;
684 return 0;
685 }
686
687 return ret_errno(EINVAL);
688 }
689
690 int config_ip_prefix(struct in_addr *addr)
691 {
692 if (IN_CLASSA(addr->s_addr))
693 return 32 - IN_CLASSA_NSHIFT;
694
695 if (IN_CLASSB(addr->s_addr))
696 return 32 - IN_CLASSB_NSHIFT;
697
698 if (IN_CLASSC(addr->s_addr))
699 return 32 - IN_CLASSC_NSHIFT;
700
701 return 0;
702 }
703
704 int network_ifname(char *valuep, const char *value, size_t size)
705 {
706 size_t retlen;
707
708 if (!valuep || !value)
709 return ret_errno(EINVAL);
710
711 retlen = strlcpy(valuep, value, size);
712 if (retlen >= size)
713 ERROR("Network device name \"%s\" is too long (>= %zu)", value, size);
714
715 return 0;
716 }
717
718 bool lxc_config_net_is_hwaddr(const char *line)
719 {
720 unsigned index;
721 char tmp[7];
722
723 if (!strnequal(line, "lxc.net", 7))
724 return false;
725
726 if (strnequal(line, "lxc.net.hwaddr", 14))
727 return true;
728
729 if (strnequal(line, "lxc.network.hwaddr", 18))
730 return true;
731
732 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
733 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
734 return strnequal(tmp, "hwaddr", 6);
735
736 return false;
737 }
738
739 void rand_complete_hwaddr(char *hwaddr)
740 {
741 const char hex[] = "0123456789abcdef";
742 char *curs = hwaddr;
743 #ifdef HAVE_RAND_R
744 unsigned int seed;
745
746 seed = randseed(false);
747 #else
748
749 (void)randseed(true);
750 #endif
751
752 while (*curs != '\0' && *curs != '\n') {
753 if (*curs == 'x' || *curs == 'X') {
754 if (curs - hwaddr == 1) {
755 /* ensure address is unicast */
756 #ifdef HAVE_RAND_R
757 *curs = hex[rand_r(&seed) & 0x0E];
758 } else {
759 *curs = hex[rand_r(&seed) & 0x0F];
760 #else
761 *curs = hex[rand() & 0x0E];
762 } else {
763 *curs = hex[rand() & 0x0F];
764 #endif
765 }
766 }
767 curs++;
768 }
769 }
770
771 bool new_hwaddr(char *hwaddr)
772 {
773 int ret;
774 #ifdef HAVE_RAND_R
775 unsigned int seed;
776
777 seed = randseed(false);
778
779 ret = strnprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
780 rand_r(&seed) % 255, rand_r(&seed) % 255);
781 #else
782
783 (void)randseed(true);
784
785 ret = strnprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
786 rand() % 255, rand() % 255);
787 #endif
788 if (ret < 0)
789 return log_error_errno(false, EIO, "Failed to call strnprintf()");
790
791 return true;
792 }
793
794 int lxc_get_conf_str(char *retv, int inlen, const char *value)
795 {
796 size_t value_len;
797
798 if (!value)
799 return 0;
800
801 value_len = strlen(value);
802 if (retv && inlen >= value_len + 1)
803 memcpy(retv, value, value_len + 1);
804
805 return value_len;
806 }
807
808 int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
809 {
810 int len;
811 int fulllen = 0;
812
813 if (!retv)
814 inlen = 0;
815 else
816 memset(retv, 0, inlen);
817
818 strprint(retv, inlen, "%d", v);
819
820 return fulllen;
821 }
822
823 int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
824 {
825 int len;
826 int fulllen = 0;
827
828 if (!retv)
829 inlen = 0;
830 else
831 memset(retv, 0, inlen);
832
833 strprint(retv, inlen, "%d", v);
834
835 return fulllen;
836 }
837
838 int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
839 {
840 int len;
841 int fulllen = 0;
842
843 if (!retv)
844 inlen = 0;
845 else
846 memset(retv, 0, inlen);
847
848 strprint(retv, inlen, "%zu", v);
849
850 return fulllen;
851 }
852
853 int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
854 {
855 int len;
856 int fulllen = 0;
857
858 if (!retv)
859 inlen = 0;
860 else
861 memset(retv, 0, inlen);
862
863 strprint(retv, inlen, "%"PRIu64, v);
864
865 return fulllen;
866 }
867
868 static int lxc_container_name_to_pid(const char *lxcname_or_pid,
869 const char *lxcpath)
870 {
871 int ret;
872 signed long int pid;
873 char *err = NULL;
874
875 pid = strtol(lxcname_or_pid, &err, 10);
876 if (*err != '\0' || pid < 1) {
877 __put_lxc_container struct lxc_container *c = NULL;
878
879 c = lxc_container_new(lxcname_or_pid, lxcpath);
880 if (!c)
881 return log_error_errno(-EINVAL, EINVAL, "\"%s\" is not a valid pid nor a container name", lxcname_or_pid);
882
883 if (!c->may_control(c))
884 return log_error_errno(-EPERM, EPERM, "Insufficient privileges to control container \"%s\"", c->name);
885
886 pid = c->init_pid(c);
887 if (pid < 1)
888 return log_error_errno(-EINVAL, EINVAL, "Container \"%s\" is not running", c->name);
889
890 }
891
892 ret = kill(pid, 0);
893 if (ret < 0)
894 return log_error_errno(-errno, errno, "Failed to send signal to pid %d", (int)pid);
895
896 return pid;
897 }
898
899 int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath,
900 const char *namespace)
901 {
902 __do_free char *dup = NULL;
903 int fd, pid;
904 char *lastslash;
905
906 if (nsfd_path[0] == '/') {
907 return open(nsfd_path, O_RDONLY | O_CLOEXEC);
908 }
909
910 lastslash = strrchr(nsfd_path, '/');
911 if (lastslash) {
912 dup = strdup(nsfd_path);
913 if (!dup)
914 return ret_errno(ENOMEM);
915
916 dup[lastslash - nsfd_path] = '\0';
917 lxcpath = lastslash + 1;
918 nsfd_path = lastslash + 1;
919 }
920
921 pid = lxc_container_name_to_pid(nsfd_path, lxcpath);
922 if (pid < 0)
923 return pid;
924
925 fd = lxc_preserve_ns(pid, namespace);
926 if (fd < 0)
927 return -errno;
928
929 return fd;
930 }
931
932 struct signame {
933 int num;
934 const char *name;
935 };
936
937 static const struct signame signames[] = {
938 { SIGHUP, "HUP" },
939 { SIGINT, "INT" },
940 { SIGQUIT, "QUIT" },
941 { SIGILL, "ILL" },
942 { SIGABRT, "ABRT" },
943 { SIGFPE, "FPE" },
944 { SIGKILL, "KILL" },
945 { SIGSEGV, "SEGV" },
946 { SIGPIPE, "PIPE" },
947 { SIGALRM, "ALRM" },
948 { SIGTERM, "TERM" },
949 { SIGUSR1, "USR1" },
950 { SIGUSR2, "USR2" },
951 { SIGCHLD, "CHLD" },
952 { SIGCONT, "CONT" },
953 { SIGSTOP, "STOP" },
954 { SIGTSTP, "TSTP" },
955 { SIGTTIN, "TTIN" },
956 { SIGTTOU, "TTOU" },
957 #ifdef SIGTRAP
958 { SIGTRAP, "TRAP" },
959 #endif
960 #ifdef SIGIOT
961 { SIGIOT, "IOT" },
962 #endif
963 #ifdef SIGEMT
964 { SIGEMT, "EMT" },
965 #endif
966 #ifdef SIGBUS
967 { SIGBUS, "BUS" },
968 #endif
969 #ifdef SIGSTKFLT
970 { SIGSTKFLT, "STKFLT" },
971 #endif
972 #ifdef SIGCLD
973 { SIGCLD, "CLD" },
974 #endif
975 #ifdef SIGURG
976 { SIGURG, "URG" },
977 #endif
978 #ifdef SIGXCPU
979 { SIGXCPU, "XCPU" },
980 #endif
981 #ifdef SIGXFSZ
982 { SIGXFSZ, "XFSZ" },
983 #endif
984 #ifdef SIGVTALRM
985 { SIGVTALRM, "VTALRM" },
986 #endif
987 #ifdef SIGPROF
988 { SIGPROF, "PROF" },
989 #endif
990 #ifdef SIGWINCH
991 { SIGWINCH, "WINCH" },
992 #endif
993 #ifdef SIGIO
994 { SIGIO, "IO" },
995 #endif
996 #ifdef SIGPOLL
997 { SIGPOLL, "POLL" },
998 #endif
999 #ifdef SIGINFO
1000 { SIGINFO, "INFO" },
1001 #endif
1002 #ifdef SIGLOST
1003 { SIGLOST, "LOST" },
1004 #endif
1005 #ifdef SIGPWR
1006 { SIGPWR, "PWR" },
1007 #endif
1008 #ifdef SIGUNUSED
1009 { SIGUNUSED, "UNUSED" },
1010 #endif
1011 #ifdef SIGSYS
1012 { SIGSYS, "SYS" },
1013 #endif
1014 };
1015
1016 static int sig_num(const char *sig)
1017 {
1018 int ret;
1019 unsigned int signum;
1020
1021 ret = lxc_safe_uint(sig, &signum);
1022 if (ret < 0)
1023 return ret;
1024
1025 return signum;
1026 }
1027
1028 static int rt_sig_num(const char *signame)
1029 {
1030 bool rtmax;
1031 int sig_n = 0;
1032
1033 if (is_empty_string(signame))
1034 return ret_errno(EINVAL);
1035
1036 if (strncasecmp(signame, "max-", STRLITERALLEN("max-")) == 0) {
1037 rtmax = true;
1038 signame += STRLITERALLEN("max-");
1039 } else if (strncasecmp(signame, "min+", STRLITERALLEN("min+")) == 0) {
1040 rtmax = false;
1041 signame += STRLITERALLEN("min+");
1042 } else {
1043 return ret_errno(EINVAL);
1044 }
1045
1046 if (is_empty_string(signame) || !isdigit(*signame))
1047 return ret_errno(EINVAL);
1048
1049 sig_n = sig_num(signame);
1050 if (sig_n < 0 || sig_n > SIGRTMAX - SIGRTMIN)
1051 return ret_errno(EINVAL);
1052
1053 if (rtmax)
1054 sig_n = SIGRTMAX - sig_n;
1055 else
1056 sig_n = SIGRTMIN + sig_n;
1057
1058 return sig_n;
1059 }
1060
1061 int sig_parse(const char *signame)
1062 {
1063 if (isdigit(*signame))
1064 return sig_num(signame);
1065
1066 if (strncasecmp(signame, "sig", STRLITERALLEN("sig")) == 0) {
1067 signame += STRLITERALLEN("sig");
1068 if (strncasecmp(signame, "rt", STRLITERALLEN("rt")) == 0)
1069 return rt_sig_num(signame + STRLITERALLEN("rt"));
1070
1071 for (size_t n = 0; n < ARRAY_SIZE(signames); n++)
1072 if (strcasecmp(signames[n].name, signame) == 0)
1073 return signames[n].num;
1074 }
1075
1076 return ret_errno(EINVAL);
1077 }