]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile.c
Merge pull request #3562 from Drachenfels-GmbH/seccomp-fixes
[mirror_lxc.git] / src / lxc / confile.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #define __STDC_FORMAT_MACROS
7 #include <arpa/inet.h>
8 #include <ctype.h>
9 #include <dirent.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <inttypes.h>
13 #include <net/if.h>
14 #include <netinet/in.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/param.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h>
23 #include <syslog.h>
24 #include <time.h>
25 #include <unistd.h>
26
27 #include "af_unix.h"
28 #include "conf.h"
29 #include "config.h"
30 #include "confile.h"
31 #include "confile_utils.h"
32 #include "../include/netns_ifaddrs.h"
33 #include "log.h"
34 #include "lxcseccomp.h"
35 #include "macro.h"
36 #include "memory_utils.h"
37 #include "network.h"
38 #include "parse.h"
39 #include "storage.h"
40 #include "utils.h"
41
42 #if HAVE_SYS_PERSONALITY_H
43 #include <sys/personality.h>
44 #endif
45
46 #ifndef HAVE_STRLCPY
47 #include "include/strlcpy.h"
48 #endif
49
50 #ifndef HAVE_STRLCAT
51 #include "include/strlcat.h"
52 #endif
53
54 lxc_log_define(confile, lxc);
55
56 #define lxc_config_define(name) \
57 __hot static int set_config_##name(const char *, const char *, \
58 struct lxc_conf *, void *); \
59 __hot static int get_config_##name(const char *, char *, int, \
60 struct lxc_conf *, void *); \
61 __hot static int clr_config_##name(const char *, struct lxc_conf *, \
62 void *);
63
64 lxc_config_define(autodev);
65 lxc_config_define(autodev_tmpfs_size);
66 lxc_config_define(apparmor_allow_incomplete);
67 lxc_config_define(apparmor_allow_nesting);
68 lxc_config_define(apparmor_profile);
69 lxc_config_define(apparmor_raw);
70 lxc_config_define(cap_drop);
71 lxc_config_define(cap_keep);
72 lxc_config_define(cgroup_controller);
73 lxc_config_define(cgroup2_controller);
74 lxc_config_define(cgroup_dir);
75 lxc_config_define(cgroup_monitor_dir);
76 lxc_config_define(cgroup_container_dir);
77 lxc_config_define(cgroup_container_inner_dir);
78 lxc_config_define(cgroup_relative);
79 lxc_config_define(console_buffer_size);
80 lxc_config_define(console_logfile);
81 lxc_config_define(console_path);
82 lxc_config_define(console_rotate);
83 lxc_config_define(console_size);
84 lxc_config_define(environment);
85 lxc_config_define(ephemeral);
86 lxc_config_define(execute_cmd);
87 lxc_config_define(group);
88 lxc_config_define(hooks);
89 lxc_config_define(hooks_version);
90 lxc_config_define(idmaps);
91 lxc_config_define(includefiles);
92 lxc_config_define(init_cmd);
93 lxc_config_define(init_cwd);
94 lxc_config_define(init_gid);
95 lxc_config_define(init_uid);
96 lxc_config_define(keyring_session);
97 lxc_config_define(log_file);
98 lxc_config_define(log_level);
99 lxc_config_define(log_syslog);
100 lxc_config_define(monitor);
101 lxc_config_define(monitor_signal_pdeath);
102 lxc_config_define(mount);
103 lxc_config_define(mount_auto);
104 lxc_config_define(mount_fstab);
105 lxc_config_define(namespace_clone);
106 lxc_config_define(namespace_keep);
107 lxc_config_define(time_offset_boot);
108 lxc_config_define(time_offset_monotonic);
109 lxc_config_define(namespace_share);
110 lxc_config_define(net);
111 lxc_config_define(net_flags);
112 lxc_config_define(net_hwaddr);
113 lxc_config_define(net_ipv4_address);
114 lxc_config_define(net_ipv4_gateway);
115 lxc_config_define(net_ipv6_address);
116 lxc_config_define(net_ipv6_gateway);
117 lxc_config_define(net_link);
118 lxc_config_define(net_l2proxy);
119 lxc_config_define(net_macvlan_mode);
120 lxc_config_define(net_ipvlan_mode);
121 lxc_config_define(net_ipvlan_isolation);
122 lxc_config_define(net_mtu);
123 lxc_config_define(net_name);
124 lxc_config_define(net_nic);
125 lxc_config_define(net_script_down);
126 lxc_config_define(net_script_up);
127 lxc_config_define(net_type);
128 lxc_config_define(net_veth_mode);
129 lxc_config_define(net_veth_pair);
130 lxc_config_define(net_veth_ipv4_route);
131 lxc_config_define(net_veth_ipv6_route);
132 lxc_config_define(net_veth_vlan_id);
133 lxc_config_define(net_veth_vlan_tagged_id);
134 lxc_config_define(net_vlan_id);
135 lxc_config_define(no_new_privs);
136 lxc_config_define(personality);
137 lxc_config_define(prlimit);
138 lxc_config_define(pty_max);
139 lxc_config_define(rootfs_managed);
140 lxc_config_define(rootfs_mount);
141 lxc_config_define(rootfs_options);
142 lxc_config_define(rootfs_path);
143 lxc_config_define(seccomp_profile);
144 lxc_config_define(seccomp_allow_nesting);
145 lxc_config_define(seccomp_notify_cookie);
146 lxc_config_define(seccomp_notify_proxy);
147 lxc_config_define(selinux_context);
148 lxc_config_define(selinux_context_keyring);
149 lxc_config_define(signal_halt);
150 lxc_config_define(signal_reboot);
151 lxc_config_define(signal_stop);
152 lxc_config_define(start);
153 lxc_config_define(tty_max);
154 lxc_config_define(tty_dir);
155 lxc_config_define(uts_name);
156 lxc_config_define(sysctl);
157 lxc_config_define(proc);
158
159 /*
160 * Important Note:
161 * If a new config option is added to this table, be aware that
162 * the order in which the options are places into the table matters.
163 * That means that more specific options of a namespace have to be
164 * placed above more generic ones.
165 *
166 * For instance: If lxc.ab is placed before lxc.ab.c, the config option
167 * lxc.ab.c will always be matched to lxc.ab. That is, the lxc.ab.c option
168 * has to be placed above lxc.ab.
169 */
170 static struct lxc_config_t config_jump_table[] = {
171 { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
172 { "lxc.apparmor.profile", set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
173 { "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
174 { "lxc.apparmor.allow_nesting", set_config_apparmor_allow_nesting, get_config_apparmor_allow_nesting, clr_config_apparmor_allow_nesting, },
175 { "lxc.apparmor.raw", set_config_apparmor_raw, get_config_apparmor_raw, clr_config_apparmor_raw, },
176 { "lxc.autodev.tmpfs.size", set_config_autodev_tmpfs_size, get_config_autodev_tmpfs_size, clr_config_autodev_tmpfs_size, },
177 { "lxc.autodev", set_config_autodev, get_config_autodev, clr_config_autodev, },
178 { "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
179 { "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
180 { "lxc.cgroup2", set_config_cgroup2_controller, get_config_cgroup2_controller, clr_config_cgroup2_controller, },
181 { "lxc.cgroup.dir.monitor", set_config_cgroup_monitor_dir, get_config_cgroup_monitor_dir, clr_config_cgroup_monitor_dir, },
182 { "lxc.cgroup.dir.container.inner", set_config_cgroup_container_inner_dir, get_config_cgroup_container_inner_dir, clr_config_cgroup_container_inner_dir, },
183 { "lxc.cgroup.dir.container", set_config_cgroup_container_dir, get_config_cgroup_container_dir, clr_config_cgroup_container_dir, },
184 { "lxc.cgroup.dir", set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
185 { "lxc.cgroup.relative", set_config_cgroup_relative, get_config_cgroup_relative, clr_config_cgroup_relative, },
186 { "lxc.cgroup", set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
187 { "lxc.console.buffer.size", set_config_console_buffer_size, get_config_console_buffer_size, clr_config_console_buffer_size, },
188 { "lxc.console.logfile", set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
189 { "lxc.console.path", set_config_console_path, get_config_console_path, clr_config_console_path, },
190 { "lxc.console.rotate", set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
191 { "lxc.console.size", set_config_console_size, get_config_console_size, clr_config_console_size, },
192 { "lxc.environment", set_config_environment, get_config_environment, clr_config_environment, },
193 { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
194 { "lxc.execute.cmd", set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
195 { "lxc.group", set_config_group, get_config_group, clr_config_group, },
196 { "lxc.hook.autodev", set_config_hooks, get_config_hooks, clr_config_hooks, },
197 { "lxc.hook.clone", set_config_hooks, get_config_hooks, clr_config_hooks, },
198 { "lxc.hook.destroy", set_config_hooks, get_config_hooks, clr_config_hooks, },
199 { "lxc.hook.mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
200 { "lxc.hook.post-stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
201 { "lxc.hook.pre-mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
202 { "lxc.hook.pre-start", set_config_hooks, get_config_hooks, clr_config_hooks, },
203 { "lxc.hook.start", set_config_hooks, get_config_hooks, clr_config_hooks, },
204 { "lxc.hook.start-host", set_config_hooks, get_config_hooks, clr_config_hooks, },
205 { "lxc.hook.stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
206 { "lxc.hook.version", set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, },
207 { "lxc.hook", set_config_hooks, get_config_hooks, clr_config_hooks, },
208 { "lxc.idmap", set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
209 { "lxc.include", set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
210 { "lxc.init.cmd", set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
211 { "lxc.init.gid", set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
212 { "lxc.init.uid", set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
213 { "lxc.init.cwd", set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, },
214 { "lxc.keyring.session", set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session },
215 { "lxc.log.file", set_config_log_file, get_config_log_file, clr_config_log_file, },
216 { "lxc.log.level", set_config_log_level, get_config_log_level, clr_config_log_level, },
217 { "lxc.log.syslog", set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
218 { "lxc.monitor.unshare", set_config_monitor, get_config_monitor, clr_config_monitor, },
219 { "lxc.monitor.signal.pdeath", set_config_monitor_signal_pdeath, get_config_monitor_signal_pdeath, clr_config_monitor_signal_pdeath, },
220 { "lxc.mount.auto", set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
221 { "lxc.mount.entry", set_config_mount, get_config_mount, clr_config_mount, },
222 { "lxc.mount.fstab", set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
223 { "lxc.namespace.clone", set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
224 { "lxc.namespace.keep", set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
225 { "lxc.namespace.share", set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
226 { "lxc.time.offset.boot", set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, },
227 { "lxc.time.offset.monotonic", set_config_time_offset_monotonic, get_config_time_offset_monotonic, clr_config_time_offset_monotonic, },
228 { "lxc.net.flags", set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
229 { "lxc.net.hwaddr", set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
230 { "lxc.net.ipv4.address", set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
231 { "lxc.net.ipv4.gateway", set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
232 { "lxc.net.ipv6.address", set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
233 { "lxc.net.ipv6.gateway", set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
234 { "lxc.net.link", set_config_net_link, get_config_net_link, clr_config_net_link, },
235 { "lxc.net.l2proxy", set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
236 { "lxc.net.macvlan.mode", set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
237 { "lxc.net.ipvlan.mode", set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
238 { "lxc.net.ipvlan.isolation", set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
239 { "lxc.net.mtu", set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
240 { "lxc.net.name", set_config_net_name, get_config_net_name, clr_config_net_name, },
241 { "lxc.net.script.down", set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
242 { "lxc.net.script.up", set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
243 { "lxc.net.type", set_config_net_type, get_config_net_type, clr_config_net_type, },
244 { "lxc.net.vlan.id", set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
245 { "lxc.net.veth.mode", set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
246 { "lxc.net.veth.pair", set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
247 { "lxc.net.veth.ipv4.route", set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
248 { "lxc.net.veth.ipv6.route", set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
249 { "lxc.net.veth.vlan.id", set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
250 { "lxc.net.veth.vlan.tagged.id", set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
251 { "lxc.net.", set_config_net_nic, get_config_net_nic, clr_config_net_nic, },
252 { "lxc.net", set_config_net, get_config_net, clr_config_net, },
253 { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
254 { "lxc.prlimit", set_config_prlimit, get_config_prlimit, clr_config_prlimit, },
255 { "lxc.pty.max", set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
256 { "lxc.rootfs.managed", set_config_rootfs_managed, get_config_rootfs_managed, clr_config_rootfs_managed, },
257 { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
258 { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
259 { "lxc.rootfs.path", set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
260 { "lxc.seccomp.allow_nesting", set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, },
261 { "lxc.seccomp.notify.cookie", set_config_seccomp_notify_cookie, get_config_seccomp_notify_cookie, clr_config_seccomp_notify_cookie, },
262 { "lxc.seccomp.notify.proxy", set_config_seccomp_notify_proxy, get_config_seccomp_notify_proxy, clr_config_seccomp_notify_proxy, },
263 { "lxc.seccomp.profile", set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
264 { "lxc.selinux.context.keyring", set_config_selinux_context_keyring, get_config_selinux_context_keyring, clr_config_selinux_context_keyring },
265 { "lxc.selinux.context", set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
266 { "lxc.signal.halt", set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
267 { "lxc.signal.reboot", set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
268 { "lxc.signal.stop", set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
269 { "lxc.start.auto", set_config_start, get_config_start, clr_config_start, },
270 { "lxc.start.delay", set_config_start, get_config_start, clr_config_start, },
271 { "lxc.start.order", set_config_start, get_config_start, clr_config_start, },
272 { "lxc.tty.dir", set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
273 { "lxc.tty.max", set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
274 { "lxc.uts.name", set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
275 { "lxc.sysctl", set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
276 { "lxc.proc", set_config_proc, get_config_proc, clr_config_proc, },
277 };
278
279 static const size_t config_jump_table_size = sizeof(config_jump_table) / sizeof(struct lxc_config_t);
280
281 struct lxc_config_t *lxc_get_config_exact(const char *key)
282 {
283 size_t i;
284
285 for (i = 0; i < config_jump_table_size; i++)
286 if (!strcmp(config_jump_table[i].name, key))
287 return &config_jump_table[i];
288
289 return NULL;
290 }
291
292
293 struct lxc_config_t *lxc_get_config(const char *key)
294 {
295 size_t i;
296
297 for (i = 0; i < config_jump_table_size; i++)
298 if (!strncmp(config_jump_table[i].name, key, strlen(config_jump_table[i].name)))
299 return &config_jump_table[i];
300
301 return NULL;
302 }
303
304 static int set_config_net(const char *key, const char *value,
305 struct lxc_conf *lxc_conf, void *data)
306 {
307 if (!lxc_config_value_empty(value)) {
308 ERROR("lxc.net must not have a value");
309 return -1;
310 }
311
312 return clr_config_net(key, lxc_conf, data);
313 }
314
315 static int set_config_net_type(const char *key, const char *value,
316 struct lxc_conf *lxc_conf, void *data)
317 {
318 struct lxc_netdev *netdev = data;
319
320 if (lxc_config_value_empty(value))
321 return clr_config_net_type(key, lxc_conf, data);
322
323 if (!netdev)
324 return -1;
325
326 if (strcmp(value, "veth") == 0) {
327 netdev->type = LXC_NET_VETH;
328 lxc_list_init(&netdev->priv.veth_attr.ipv4_routes);
329 lxc_list_init(&netdev->priv.veth_attr.ipv6_routes);
330 lxc_list_init(&netdev->priv.veth_attr.vlan_tagged_ids);
331 if (!lxc_veth_flag_to_mode(netdev->priv.veth_attr.mode))
332 lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge");
333 } else if (strcmp(value, "macvlan") == 0) {
334 netdev->type = LXC_NET_MACVLAN;
335 if (!lxc_macvlan_flag_to_mode(netdev->priv.veth_attr.mode))
336 lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
337 } else if (strcmp(value, "ipvlan") == 0) {
338 netdev->type = LXC_NET_IPVLAN;
339 if (!lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode))
340 lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, "l3");
341 if (!lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation))
342 lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, "bridge");
343 } else if (strcmp(value, "vlan") == 0) {
344 netdev->type = LXC_NET_VLAN;
345 } else if (strcmp(value, "phys") == 0) {
346 netdev->type = LXC_NET_PHYS;
347 } else if (strcmp(value, "empty") == 0) {
348 netdev->type = LXC_NET_EMPTY;
349 } else if (strcmp(value, "none") == 0) {
350 netdev->type = LXC_NET_NONE;
351 } else {
352 ERROR("Invalid network type %s", value);
353 return -1;
354 }
355
356 return 0;
357 }
358
359 static int set_config_net_flags(const char *key, const char *value,
360 struct lxc_conf *lxc_conf, void *data)
361 {
362 struct lxc_netdev *netdev = data;
363
364 if (lxc_config_value_empty(value))
365 return clr_config_net_flags(key, lxc_conf, data);
366
367 if (!netdev)
368 return -1;
369
370 netdev->flags |= IFF_UP;
371
372 return 0;
373 }
374
375 static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
376 struct lxc_netdev *netdev)
377 {
378 struct netns_ifaddrs *ifaddr, *ifa;
379 int n;
380 int ret = 0;
381 const char *type_key = "lxc.net.type";
382 const char *link_key = "lxc.net.link";
383 const char *tmpvalue = "phys";
384
385 if (netns_getifaddrs(&ifaddr, -1, &(bool){false}) < 0) {
386 SYSERROR("Failed to get network interfaces");
387 return -1;
388 }
389
390 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
391 if (!ifa->ifa_addr)
392 continue;
393
394 if (ifa->ifa_addr->sa_family != AF_PACKET)
395 continue;
396
397 if (!strncmp(value, ifa->ifa_name, strlen(value) - 1)) {
398 ret = set_config_net_type(type_key, tmpvalue, lxc_conf,
399 netdev);
400 if (!ret) {
401 ret = set_config_net_link(
402 link_key, ifa->ifa_name, lxc_conf, netdev);
403 if (ret) {
404 ERROR("Failed to create matched ifnames");
405 break;
406 }
407 } else {
408 ERROR("Failed to create matched ifnames");
409 break;
410 }
411 }
412 }
413
414 netns_freeifaddrs(ifaddr);
415 ifaddr = NULL;
416
417 return ret;
418 }
419
420 static int set_config_net_link(const char *key, const char *value,
421 struct lxc_conf *lxc_conf, void *data)
422 {
423 struct lxc_netdev *netdev = data;
424 int ret = 0;
425
426 if (lxc_config_value_empty(value))
427 return clr_config_net_link(key, lxc_conf, data);
428
429 if (!netdev)
430 return -1;
431
432 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS)
433 ret = create_matched_ifnames(value, lxc_conf, netdev);
434 else
435 ret = network_ifname(netdev->link, value, sizeof(netdev->link));
436
437 return ret;
438 }
439
440 static int set_config_net_l2proxy(const char *key, const char *value,
441 struct lxc_conf *lxc_conf, void *data)
442 {
443 struct lxc_netdev *netdev = data;
444 unsigned int val = 0;
445 int ret;
446
447 if (lxc_config_value_empty(value))
448 return clr_config_net_l2proxy(key, lxc_conf, data);
449
450 if (!netdev)
451 return ret_set_errno(-1, EINVAL);
452
453 ret = lxc_safe_uint(value, &val);
454 if (ret < 0)
455 return ret_set_errno(-1, -ret);
456
457 switch (val) {
458 case 0:
459 netdev->l2proxy = false;
460 return 0;
461 case 1:
462 netdev->l2proxy = true;
463 return 0;
464 }
465
466 return ret_set_errno(-1, EINVAL);
467 }
468
469 static int set_config_net_name(const char *key, const char *value,
470 struct lxc_conf *lxc_conf, void *data)
471 {
472 struct lxc_netdev *netdev = data;
473
474 if (lxc_config_value_empty(value))
475 return clr_config_net_name(key, lxc_conf, data);
476
477 if (!netdev)
478 return -1;
479
480 return network_ifname(netdev->name, value, sizeof(netdev->name));
481 }
482
483
484 static int set_config_net_veth_mode(const char *key, const char *value,
485 struct lxc_conf *lxc_conf, void *data)
486 {
487 struct lxc_netdev *netdev = data;
488
489 if (lxc_config_value_empty(value))
490 return clr_config_net_veth_mode(key, lxc_conf, data);
491
492 if (!netdev)
493 return -1;
494
495 return lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, value);
496 }
497
498 static int set_config_net_veth_pair(const char *key, const char *value,
499 struct lxc_conf *lxc_conf, void *data)
500 {
501 struct lxc_netdev *netdev = data;
502
503 if (lxc_config_value_empty(value))
504 return clr_config_net_veth_pair(key, lxc_conf, data);
505
506 if (!netdev)
507 return -1;
508
509 return network_ifname(netdev->priv.veth_attr.pair, value, sizeof(netdev->priv.veth_attr.pair));
510 }
511
512 static int set_config_net_veth_vlan_id(const char *key, const char *value,
513 struct lxc_conf *lxc_conf, void *data)
514 {
515 int ret;
516 struct lxc_netdev *netdev = data;
517
518 if (!netdev)
519 return ret_errno(EINVAL);
520
521 if (lxc_config_value_empty(value))
522 return clr_config_net_veth_vlan_id(key, lxc_conf, data);
523
524 if (strcmp(value, "none") == 0) {
525 netdev->priv.veth_attr.vlan_id = BRIDGE_VLAN_NONE;
526 } else {
527 unsigned short vlan_id;
528 ret = get_u16(&vlan_id, value, 0);
529 if (ret < 0)
530 return ret_errno(EINVAL);
531
532 if (vlan_id > BRIDGE_VLAN_ID_MAX)
533 return ret_errno(EINVAL);
534
535 netdev->priv.veth_attr.vlan_id = vlan_id;
536 }
537
538 netdev->priv.veth_attr.vlan_id_set = true;
539 return 0;
540 }
541
542 static int set_config_net_veth_vlan_tagged_id(const char *key, const char *value,
543 struct lxc_conf *lxc_conf, void *data)
544 {
545 __do_free struct lxc_list *list = NULL;
546 int ret;
547 unsigned short vlan_id;
548 struct lxc_netdev *netdev = data;
549
550 if (!netdev)
551 return ret_errno(EINVAL);
552
553 if (lxc_config_value_empty(value))
554 return clr_config_net_veth_vlan_tagged_id(key, lxc_conf, data);
555
556 ret = get_u16(&vlan_id, value, 0);
557 if (ret < 0)
558 ret_errno(EINVAL);
559
560 if (vlan_id > BRIDGE_VLAN_ID_MAX)
561 ret_errno(EINVAL);
562
563 list = malloc(sizeof(*list));
564 if (!list)
565 return ret_errno(ENOMEM);
566
567 lxc_list_init(list);
568 list->elem = UINT_TO_PTR(vlan_id);
569
570 lxc_list_add_tail(&netdev->priv.veth_attr.vlan_tagged_ids, move_ptr(list));
571
572 return 0;
573 }
574
575 static int set_config_net_macvlan_mode(const char *key, const char *value,
576 struct lxc_conf *lxc_conf, void *data)
577 {
578 struct lxc_netdev *netdev = data;
579
580 if (lxc_config_value_empty(value))
581 return clr_config_net_macvlan_mode(key, lxc_conf, data);
582
583 if (!netdev)
584 return -1;
585
586 return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
587 }
588
589 static int set_config_net_ipvlan_mode(const char *key, const char *value,
590 struct lxc_conf *lxc_conf, void *data)
591 {
592 struct lxc_netdev *netdev = data;
593
594 if (lxc_config_value_empty(value))
595 return clr_config_net_ipvlan_mode(key, lxc_conf, data);
596
597 if (!netdev)
598 return ret_set_errno(-1, EINVAL);
599
600 if (netdev->type != LXC_NET_IPVLAN) {
601 SYSERROR("Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value);
602 return ret_set_errno(-1, EINVAL);
603 }
604
605 return lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, value);
606 }
607
608 static int set_config_net_ipvlan_isolation(const char *key, const char *value,
609 struct lxc_conf *lxc_conf, void *data)
610 {
611 struct lxc_netdev *netdev = data;
612
613 if (lxc_config_value_empty(value))
614 return clr_config_net_ipvlan_isolation(key, lxc_conf, data);
615
616 if (!netdev)
617 return ret_set_errno(-1, EINVAL);
618
619 if (netdev->type != LXC_NET_IPVLAN) {
620 SYSERROR("Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value);
621 return ret_set_errno(-1, EINVAL);
622 }
623
624 return lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, value);
625 }
626
627 static int set_config_net_hwaddr(const char *key, const char *value,
628 struct lxc_conf *lxc_conf, void *data)
629 {
630 struct lxc_netdev *netdev = data;
631 char *new_value;
632
633 if (lxc_config_value_empty(value))
634 return clr_config_net_hwaddr(key, lxc_conf, data);
635
636 if (!netdev)
637 return -1;
638
639 new_value = strdup(value);
640 if (!new_value)
641 return -1;
642
643 rand_complete_hwaddr(new_value);
644
645 if (lxc_config_value_empty(new_value)) {
646 free(new_value);
647 netdev->hwaddr = NULL;
648 return 0;
649 }
650
651 netdev->hwaddr = new_value;
652
653 return 0;
654 }
655
656 static int set_config_net_vlan_id(const char *key, const char *value,
657 struct lxc_conf *lxc_conf, void *data)
658 {
659 int ret;
660 struct lxc_netdev *netdev = data;
661
662 if (lxc_config_value_empty(value))
663 return clr_config_net_vlan_id(key, lxc_conf, data);
664
665 if (!netdev)
666 return -1;
667
668 ret = get_u16(&netdev->priv.vlan_attr.vid, value, 0);
669 if (ret < 0)
670 return -1;
671
672 return 0;
673 }
674
675 static int set_config_net_mtu(const char *key, const char *value,
676 struct lxc_conf *lxc_conf, void *data)
677 {
678 struct lxc_netdev *netdev = data;
679
680 if (lxc_config_value_empty(value))
681 return clr_config_net_mtu(key, lxc_conf, data);
682
683 if (!netdev)
684 return -1;
685
686 return set_config_string_item(&netdev->mtu, value);
687 }
688
689 static int set_config_net_ipv4_address(const char *key, const char *value,
690 struct lxc_conf *lxc_conf, void *data)
691 {
692 int ret;
693 struct lxc_netdev *netdev = data;
694 struct lxc_inetdev *inetdev;
695 struct lxc_list *list;
696 char *cursor, *slash;
697 char *addr = NULL, *bcast = NULL, *prefix = NULL;
698
699 if (lxc_config_value_empty(value))
700 return clr_config_net_ipv4_address(key, lxc_conf, data);
701
702 if (!netdev)
703 return -1;
704
705 inetdev = malloc(sizeof(*inetdev));
706 if (!inetdev)
707 return -1;
708 memset(inetdev, 0, sizeof(*inetdev));
709
710 list = malloc(sizeof(*list));
711 if (!list) {
712 free(inetdev);
713 return -1;
714 }
715
716 lxc_list_init(list);
717 list->elem = inetdev;
718
719 addr = strdup(value);
720 if (!addr) {
721 free(inetdev);
722 free(list);
723 return -1;
724 }
725
726 cursor = strstr(addr, " ");
727 if (cursor) {
728 *cursor = '\0';
729 bcast = cursor + 1;
730 }
731
732 slash = strstr(addr, "/");
733 if (slash) {
734 *slash = '\0';
735 prefix = slash + 1;
736 }
737
738 ret = inet_pton(AF_INET, addr, &inetdev->addr);
739 if (!ret || ret < 0) {
740 SYSERROR("Invalid ipv4 address \"%s\"", value);
741 free(inetdev);
742 free(addr);
743 free(list);
744 return -1;
745 }
746
747 if (bcast) {
748 ret = inet_pton(AF_INET, bcast, &inetdev->bcast);
749 if (!ret || ret < 0) {
750 SYSERROR("Invalid ipv4 broadcast address \"%s\"", value);
751 free(inetdev);
752 free(list);
753 free(addr);
754 return -1;
755 }
756
757 }
758
759 /* No prefix specified, determine it from the network class. */
760 if (prefix) {
761 ret = lxc_safe_uint(prefix, &inetdev->prefix);
762 if (ret < 0) {
763 free(inetdev);
764 free(list);
765 free(addr);
766 return -1;
767 }
768 } else {
769 inetdev->prefix = config_ip_prefix(&inetdev->addr);
770 }
771
772 /* If no broadcast address, let compute one from the
773 * prefix and address.
774 */
775 if (!bcast) {
776 inetdev->bcast.s_addr = inetdev->addr.s_addr;
777 inetdev->bcast.s_addr |= htonl(INADDR_BROADCAST >> inetdev->prefix);
778 }
779
780 lxc_list_add_tail(&netdev->ipv4, list);
781 free(addr);
782
783 return 0;
784 }
785
786 static int set_config_net_ipv4_gateway(const char *key, const char *value,
787 struct lxc_conf *lxc_conf, void *data)
788 {
789 struct lxc_netdev *netdev = data;
790
791 if (lxc_config_value_empty(value))
792 return clr_config_net_ipv4_gateway(key, lxc_conf, data);
793
794 if (!netdev)
795 return -1;
796
797 free(netdev->ipv4_gateway);
798
799 if (strcmp(value, "auto") == 0) {
800 netdev->ipv4_gateway = NULL;
801 netdev->ipv4_gateway_auto = true;
802 } else if (strcmp(value, "dev") == 0) {
803 netdev->ipv4_gateway = NULL;
804 netdev->ipv4_gateway_auto = false;
805 netdev->ipv4_gateway_dev = true;
806 } else {
807 int ret;
808 struct in_addr *gw;
809
810 gw = malloc(sizeof(*gw));
811 if (!gw)
812 return -1;
813
814 ret = inet_pton(AF_INET, value, gw);
815 if (!ret || ret < 0) {
816 SYSERROR("Invalid ipv4 gateway address \"%s\"", value);
817 free(gw);
818 return -1;
819 }
820
821 netdev->ipv4_gateway = gw;
822 netdev->ipv4_gateway_auto = false;
823 }
824
825 return 0;
826 }
827
828 static int set_config_net_veth_ipv4_route(const char *key, const char *value,
829 struct lxc_conf *lxc_conf, void *data)
830 {
831 __do_free char *valdup = NULL;
832 __do_free struct lxc_inetdev *inetdev = NULL;
833 __do_free struct lxc_list *list = NULL;
834 int ret;
835 char *netmask, *slash;
836 struct lxc_netdev *netdev = data;
837
838 if (lxc_config_value_empty(value))
839 return clr_config_net_veth_ipv4_route(key, lxc_conf, data);
840
841 if (!netdev)
842 return ret_set_errno(-1, EINVAL);
843
844 if (netdev->type != LXC_NET_VETH) {
845 SYSERROR("Invalid ipv4 route \"%s\", can only be used with veth network", value);
846 return ret_set_errno(-1, EINVAL);
847 }
848
849 inetdev = malloc(sizeof(*inetdev));
850 if (!inetdev)
851 return -1;
852 memset(inetdev, 0, sizeof(*inetdev));
853
854 list = malloc(sizeof(*list));
855 if (!list)
856 return -1;
857
858 lxc_list_init(list);
859 list->elem = inetdev;
860
861 valdup = strdup(value);
862 if (!valdup)
863 return -1;
864
865 slash = strchr(valdup, '/');
866 if (!slash)
867 return ret_set_errno(-1, EINVAL);
868
869 *slash = '\0';
870 slash++;
871 if (*slash == '\0')
872 return ret_set_errno(-1, EINVAL);
873
874 netmask = slash;
875
876 ret = lxc_safe_uint(netmask, &inetdev->prefix);
877 if (ret < 0 || inetdev->prefix > 32)
878 return ret_set_errno(-1, EINVAL);
879
880 ret = inet_pton(AF_INET, valdup, &inetdev->addr);
881 if (!ret || ret < 0)
882 return ret_set_errno(-1, EINVAL);
883
884 lxc_list_add_tail(&netdev->priv.veth_attr.ipv4_routes, list);
885 move_ptr(inetdev);
886 move_ptr(list);
887
888 return 0;
889 }
890
891 static int set_config_net_ipv6_address(const char *key, const char *value,
892 struct lxc_conf *lxc_conf, void *data)
893 {
894 int ret;
895 struct lxc_netdev *netdev = data;
896 struct lxc_inet6dev *inet6dev;
897 struct lxc_list *list;
898 char *slash, *valdup, *netmask;
899
900 if (lxc_config_value_empty(value))
901 return clr_config_net_ipv6_address(key, lxc_conf, data);
902
903 if (!netdev)
904 return -1;
905
906 inet6dev = malloc(sizeof(*inet6dev));
907 if (!inet6dev)
908 return -1;
909 memset(inet6dev, 0, sizeof(*inet6dev));
910
911 list = malloc(sizeof(*list));
912 if (!list) {
913 free(inet6dev);
914 return -1;
915 }
916
917 lxc_list_init(list);
918 list->elem = inet6dev;
919
920 valdup = strdup(value);
921 if (!valdup) {
922 free(list);
923 free(inet6dev);
924 return -1;
925 }
926
927 inet6dev->prefix = 64;
928 slash = strstr(valdup, "/");
929 if (slash) {
930 *slash = '\0';
931 netmask = slash + 1;
932
933 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
934 if (ret < 0) {
935 free(list);
936 free(inet6dev);
937 free(valdup);
938 return -1;
939 }
940 }
941
942 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
943 if (!ret || ret < 0) {
944 SYSERROR("Invalid ipv6 address \"%s\"", valdup);
945 free(list);
946 free(inet6dev);
947 free(valdup);
948 return -1;
949 }
950
951 lxc_list_add_tail(&netdev->ipv6, list);
952 free(valdup);
953
954 return 0;
955 }
956
957 static int set_config_net_ipv6_gateway(const char *key, const char *value,
958 struct lxc_conf *lxc_conf, void *data)
959 {
960 struct lxc_netdev *netdev = data;
961
962 if (lxc_config_value_empty(value))
963 return clr_config_net_ipv6_gateway(key, lxc_conf, data);
964
965 if (!netdev)
966 return -1;
967
968 free(netdev->ipv6_gateway);
969
970 if (strcmp(value, "auto") == 0) {
971 netdev->ipv6_gateway = NULL;
972 netdev->ipv6_gateway_auto = true;
973 } else if (strcmp(value, "dev") == 0) {
974 netdev->ipv6_gateway = NULL;
975 netdev->ipv6_gateway_auto = false;
976 netdev->ipv6_gateway_dev = true;
977 } else {
978 int ret;
979 struct in6_addr *gw;
980
981 gw = malloc(sizeof(*gw));
982 if (!gw)
983 return -1;
984
985 ret = inet_pton(AF_INET6, value, gw);
986 if (!ret || ret < 0) {
987 SYSERROR("Invalid ipv6 gateway address \"%s\"", value);
988 free(gw);
989 return -1;
990 }
991
992 netdev->ipv6_gateway = gw;
993 netdev->ipv6_gateway_auto = false;
994 }
995
996 return 0;
997 }
998
999 static int set_config_net_veth_ipv6_route(const char *key, const char *value,
1000 struct lxc_conf *lxc_conf, void *data)
1001 {
1002 __do_free char *valdup = NULL;
1003 __do_free struct lxc_inet6dev *inet6dev = NULL;
1004 __do_free struct lxc_list *list = NULL;
1005 int ret;
1006 char *netmask, *slash;
1007 struct lxc_netdev *netdev = data;
1008
1009 if (lxc_config_value_empty(value))
1010 return clr_config_net_veth_ipv6_route(key, lxc_conf, data);
1011
1012 if (!netdev)
1013 return ret_set_errno(-1, EINVAL);
1014
1015 if (netdev->type != LXC_NET_VETH) {
1016 SYSERROR("Invalid ipv6 route \"%s\", can only be used with veth network", value);
1017 return ret_set_errno(-1, EINVAL);
1018 }
1019
1020 inet6dev = malloc(sizeof(*inet6dev));
1021 if (!inet6dev)
1022 return -1;
1023 memset(inet6dev, 0, sizeof(*inet6dev));
1024
1025 list = malloc(sizeof(*list));
1026 if (!list)
1027 return -1;
1028
1029 lxc_list_init(list);
1030 list->elem = inet6dev;
1031
1032 valdup = strdup(value);
1033 if (!valdup)
1034 return -1;
1035
1036 slash = strchr(valdup, '/');
1037 if (!slash)
1038 return ret_set_errno(-1, EINVAL);
1039
1040 *slash = '\0';
1041 slash++;
1042 if (*slash == '\0')
1043 return ret_set_errno(-1, EINVAL);
1044
1045 netmask = slash;
1046
1047 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
1048 if (ret < 0 || inet6dev->prefix > 128)
1049 return ret_set_errno(-1, EINVAL);
1050
1051 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
1052 if (!ret || ret < 0)
1053 return ret_set_errno(-1, EINVAL);
1054
1055 lxc_list_add_tail(&netdev->priv.veth_attr.ipv6_routes, list);
1056 move_ptr(inet6dev);
1057 move_ptr(list);
1058
1059 return 0;
1060 }
1061
1062 static int set_config_net_script_up(const char *key, const char *value,
1063 struct lxc_conf *lxc_conf, void *data)
1064 {
1065 struct lxc_netdev *netdev = data;
1066
1067 if (lxc_config_value_empty(value))
1068 return clr_config_net_script_up(key, lxc_conf, data);
1069
1070 if (!netdev)
1071 return -1;
1072
1073 return set_config_string_item(&netdev->upscript, value);
1074 }
1075
1076 static int set_config_net_script_down(const char *key, const char *value,
1077 struct lxc_conf *lxc_conf, void *data)
1078 {
1079 struct lxc_netdev *netdev = data;
1080
1081 if (lxc_config_value_empty(value))
1082 return clr_config_net_script_down(key, lxc_conf, data);
1083
1084 if (!netdev)
1085 return -1;
1086
1087 return set_config_string_item(&netdev->downscript, value);
1088 }
1089
1090 static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
1091 {
1092 struct lxc_list *hooklist;
1093
1094 hooklist = malloc(sizeof(*hooklist));
1095 if (!hooklist) {
1096 free(hook);
1097 return -1;
1098 }
1099
1100 hooklist->elem = hook;
1101 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
1102
1103 return 0;
1104 }
1105
1106 static int set_config_seccomp_allow_nesting(const char *key, const char *value,
1107 struct lxc_conf *lxc_conf, void *data)
1108 {
1109 #ifdef HAVE_SECCOMP
1110 if (lxc_config_value_empty(value))
1111 return clr_config_seccomp_allow_nesting(key, lxc_conf, NULL);
1112
1113 if (lxc_safe_uint(value, &lxc_conf->seccomp.allow_nesting) < 0)
1114 return -1;
1115
1116 if (lxc_conf->seccomp.allow_nesting > 1)
1117 return ret_set_errno(-1, EINVAL);
1118
1119 return 0;
1120 #else
1121 errno = ENOSYS;
1122 return -1;
1123 #endif
1124 }
1125
1126 static int set_config_seccomp_notify_cookie(const char *key, const char *value,
1127 struct lxc_conf *lxc_conf, void *data)
1128 {
1129 #ifdef HAVE_SECCOMP_NOTIFY
1130 return set_config_string_item(&lxc_conf->seccomp.notifier.cookie, value);
1131 #else
1132 return ret_set_errno(-1, ENOSYS);
1133 #endif
1134 }
1135
1136 static int set_config_seccomp_notify_proxy(const char *key, const char *value,
1137 struct lxc_conf *lxc_conf, void *data)
1138 {
1139 #ifdef HAVE_SECCOMP_NOTIFY
1140 const char *offset;
1141
1142 if (lxc_config_value_empty(value))
1143 return clr_config_seccomp_notify_proxy(key, lxc_conf, NULL);
1144
1145 if (strncmp(value, "unix:", 5) != 0)
1146 return ret_set_errno(-1, EINVAL);
1147
1148 offset = value + 5;
1149 if (lxc_unix_sockaddr(&lxc_conf->seccomp.notifier.proxy_addr, offset) < 0)
1150 return -1;
1151
1152 return 0;
1153 #else
1154 return ret_set_errno(-1, ENOSYS);
1155 #endif
1156 }
1157
1158 static int set_config_seccomp_profile(const char *key, const char *value,
1159 struct lxc_conf *lxc_conf, void *data)
1160 {
1161 return set_config_path_item(&lxc_conf->seccomp.seccomp, value);
1162 }
1163
1164 static int set_config_execute_cmd(const char *key, const char *value,
1165 struct lxc_conf *lxc_conf, void *data)
1166 {
1167 return set_config_path_item(&lxc_conf->execute_cmd, value);
1168 }
1169
1170 static int set_config_init_cmd(const char *key, const char *value,
1171 struct lxc_conf *lxc_conf, void *data)
1172 {
1173 return set_config_path_item(&lxc_conf->init_cmd, value);
1174 }
1175
1176 static int set_config_init_cwd(const char *key, const char *value,
1177 struct lxc_conf *lxc_conf, void *data)
1178 {
1179 return set_config_path_item(&lxc_conf->init_cwd, value);
1180 }
1181
1182 static int set_config_init_uid(const char *key, const char *value,
1183 struct lxc_conf *lxc_conf, void *data)
1184 {
1185 unsigned int init_uid;
1186
1187 if (lxc_config_value_empty(value)) {
1188 lxc_conf->init_uid = 0;
1189 return 0;
1190 }
1191
1192 if (lxc_safe_uint(value, &init_uid) < 0)
1193 return -1;
1194
1195 lxc_conf->init_uid = init_uid;
1196
1197 return 0;
1198 }
1199
1200 static int set_config_init_gid(const char *key, const char *value,
1201 struct lxc_conf *lxc_conf, void *data)
1202 {
1203 unsigned int init_gid;
1204
1205 if (lxc_config_value_empty(value)) {
1206 lxc_conf->init_gid = 0;
1207 return 0;
1208 }
1209
1210 if (lxc_safe_uint(value, &init_gid) < 0)
1211 return -1;
1212
1213 lxc_conf->init_gid = init_gid;
1214
1215 return 0;
1216 }
1217
1218 static int set_config_hooks(const char *key, const char *value,
1219 struct lxc_conf *lxc_conf, void *data)
1220 {
1221 char *copy;
1222
1223 if (lxc_config_value_empty(value))
1224 return lxc_clear_hooks(lxc_conf, key);
1225
1226 if (strcmp(key + 4, "hook") == 0) {
1227 ERROR("lxc.hook must not have a value");
1228 return -1;
1229 }
1230
1231 copy = strdup(value);
1232 if (!copy)
1233 return -1;
1234
1235 if (strcmp(key + 9, "pre-start") == 0)
1236 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
1237 else if (strcmp(key + 9, "start-host") == 0)
1238 return add_hook(lxc_conf, LXCHOOK_START_HOST, copy);
1239 else if (strcmp(key + 9, "pre-mount") == 0)
1240 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
1241 else if (strcmp(key + 9, "autodev") == 0)
1242 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
1243 else if (strcmp(key + 9, "mount") == 0)
1244 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
1245 else if (strcmp(key + 9, "start") == 0)
1246 return add_hook(lxc_conf, LXCHOOK_START, copy);
1247 else if (strcmp(key + 9, "stop") == 0)
1248 return add_hook(lxc_conf, LXCHOOK_STOP, copy);
1249 else if (strcmp(key + 9, "post-stop") == 0)
1250 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
1251 else if (strcmp(key + 9, "clone") == 0)
1252 return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
1253 else if (strcmp(key + 9, "destroy") == 0)
1254 return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
1255
1256 free(copy);
1257
1258 return -1;
1259 }
1260
1261 static int set_config_hooks_version(const char *key, const char *value,
1262 struct lxc_conf *lxc_conf, void *data)
1263 {
1264 int ret;
1265 unsigned int tmp;
1266
1267 if (lxc_config_value_empty(value))
1268 return clr_config_hooks_version(key, lxc_conf, NULL);
1269
1270 ret = lxc_safe_uint(value, &tmp);
1271 if (ret < 0)
1272 return -1;
1273
1274 if (tmp > 1) {
1275 ERROR("Invalid hook version specified. Currently only 0 "
1276 "(legacy) and 1 are supported");
1277 return -1;
1278 }
1279
1280 lxc_conf->hooks_version = tmp;
1281
1282 return 0;
1283 }
1284
1285 static int set_config_personality(const char *key, const char *value,
1286 struct lxc_conf *lxc_conf, void *data)
1287 {
1288 signed long personality = lxc_config_parse_arch(value);
1289
1290 if (personality >= 0)
1291 lxc_conf->personality = personality;
1292 else
1293 WARN("Unsupported personality \"%s\"", value);
1294
1295 return 0;
1296 }
1297
1298 static int set_config_pty_max(const char *key, const char *value,
1299 struct lxc_conf *lxc_conf, void *data)
1300 {
1301 int ret;
1302 unsigned int max = 0;
1303
1304 if (lxc_config_value_empty(value)) {
1305 lxc_conf->pty_max = 0;
1306 return 0;
1307 }
1308
1309 ret = lxc_safe_uint(value, &max);
1310 if (ret < 0)
1311 return -1;
1312
1313 lxc_conf->pty_max = max;
1314
1315 return 0;
1316 }
1317
1318 /* We only need to check whether the first byte of the key after the lxc.start.
1319 * prefix matches our expectations since they fortunately all start with a
1320 * different letter. If anything was wrong with the key we would have already
1321 * noticed when the callback was called.
1322 */
1323 static int set_config_start(const char *key, const char *value,
1324 struct lxc_conf *lxc_conf, void *data)
1325 {
1326 bool is_empty;
1327
1328 is_empty = lxc_config_value_empty(value);
1329
1330 if (*(key + 10) == 'a') { /* lxc.start.auto */
1331 if (is_empty) {
1332 lxc_conf->start_auto = 0;
1333 return 0;
1334 }
1335
1336 if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
1337 return -1;
1338
1339 if (lxc_conf->start_auto > 1)
1340 return -1;
1341
1342 return 0;
1343 } else if (*(key + 10) == 'd') { /* lxc.start.delay */
1344 if (is_empty) {
1345 lxc_conf->start_delay = 0;
1346 return 0;
1347 }
1348
1349 return lxc_safe_uint(value, &lxc_conf->start_delay);
1350 } else if (*(key + 10) == 'o') { /* lxc.start.order */
1351 if (is_empty) {
1352 lxc_conf->start_order = 0;
1353 return 0;
1354 }
1355
1356 return lxc_safe_int(value, &lxc_conf->start_order);
1357 }
1358
1359 return -1;
1360 }
1361
1362 static int set_config_monitor(const char *key, const char *value,
1363 struct lxc_conf *lxc_conf, void *data)
1364 {
1365 if (lxc_config_value_empty(value)) {
1366 lxc_conf->monitor_unshare = 0;
1367 return 0;
1368 }
1369
1370 if (strcmp(key + 12, "unshare") == 0)
1371 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1372
1373 return -1;
1374 }
1375
1376 static int set_config_monitor_signal_pdeath(const char *key, const char *value,
1377 struct lxc_conf *lxc_conf, void *data)
1378 {
1379 if (lxc_config_value_empty(value)) {
1380 lxc_conf->monitor_signal_pdeath = 0;
1381 return 0;
1382 }
1383
1384 if (strcmp(key + 12, "signal.pdeath") == 0) {
1385 int sig_n;
1386
1387 sig_n = sig_parse(value);
1388 if (sig_n < 0)
1389 return -1;
1390
1391 lxc_conf->monitor_signal_pdeath = sig_n;
1392 return 0;
1393 }
1394
1395 return -EINVAL;
1396 }
1397
1398 static int set_config_group(const char *key, const char *value,
1399 struct lxc_conf *lxc_conf, void *data)
1400 {
1401 char *groups, *token;
1402 struct lxc_list *grouplist;
1403 int ret = 0;
1404
1405 if (lxc_config_value_empty(value))
1406 return lxc_clear_groups(lxc_conf);
1407
1408 groups = strdup(value);
1409 if (!groups)
1410 return -1;
1411
1412 /* In case several groups are specified in a single line split these
1413 * groups in a single element for the list.
1414 */
1415 lxc_iterate_parts(token, groups, " \t") {
1416 grouplist = malloc(sizeof(*grouplist));
1417 if (!grouplist) {
1418 ret = -1;
1419 break;
1420 }
1421
1422 grouplist->elem = strdup(token);
1423 if (!grouplist->elem) {
1424 free(grouplist);
1425 ret = -1;
1426 break;
1427 }
1428
1429 lxc_list_add_tail(&lxc_conf->groups, grouplist);
1430 }
1431
1432 free(groups);
1433
1434 return ret;
1435 }
1436
1437 static int set_config_environment(const char *key, const char *value,
1438 struct lxc_conf *lxc_conf, void *data)
1439 {
1440 struct lxc_list *list_item = NULL;
1441
1442 if (lxc_config_value_empty(value))
1443 return lxc_clear_environment(lxc_conf);
1444
1445 list_item = malloc(sizeof(*list_item));
1446 if (!list_item)
1447 goto on_error;
1448
1449 if (!strchr(value, '=')) {
1450 const char *env_val;
1451 const char *env_key = value;
1452 const char *env_var[3] = {0};
1453
1454 env_val = getenv(env_key);
1455 if (!env_val)
1456 goto on_error;
1457
1458 env_var[0] = env_key;
1459 env_var[1] = env_val;
1460 list_item->elem = lxc_string_join("=", env_var, false);
1461 } else {
1462 list_item->elem = strdup(value);
1463 }
1464
1465 if (!list_item->elem)
1466 goto on_error;
1467
1468 lxc_list_add_tail(&lxc_conf->environment, list_item);
1469
1470 return 0;
1471
1472 on_error:
1473 free(list_item);
1474
1475 return -1;
1476 }
1477
1478 static int set_config_tty_max(const char *key, const char *value,
1479 struct lxc_conf *lxc_conf, void *data)
1480 {
1481 int ret;
1482 unsigned int nbtty = 0;
1483
1484 if (lxc_config_value_empty(value)) {
1485 lxc_conf->ttys.max = 0;
1486 return 0;
1487 }
1488
1489 ret = lxc_safe_uint(value, &nbtty);
1490 if (ret < 0)
1491 return -1;
1492
1493 lxc_conf->ttys.max = nbtty;
1494
1495 return 0;
1496 }
1497
1498 static int set_config_tty_dir(const char *key, const char *value,
1499 struct lxc_conf *lxc_conf, void *data)
1500 {
1501 return set_config_string_item_max(&lxc_conf->ttys.dir, value,
1502 NAME_MAX + 1);
1503 }
1504
1505 static int set_config_apparmor_profile(const char *key, const char *value,
1506 struct lxc_conf *lxc_conf, void *data)
1507 {
1508 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
1509 }
1510
1511 static int set_config_apparmor_allow_incomplete(const char *key,
1512 const char *value,
1513 struct lxc_conf *lxc_conf,
1514 void *data)
1515 {
1516 if (lxc_config_value_empty(value)) {
1517 lxc_conf->lsm_aa_allow_incomplete = 0;
1518 return 0;
1519 }
1520
1521 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1522 return -1;
1523
1524 if (lxc_conf->lsm_aa_allow_incomplete > 1)
1525 return -1;
1526
1527 return 0;
1528 }
1529
1530 static int set_config_apparmor_allow_nesting(const char *key,
1531 const char *value,
1532 struct lxc_conf *lxc_conf,
1533 void *data)
1534 {
1535 if (lxc_config_value_empty(value))
1536 return clr_config_apparmor_allow_nesting(key, lxc_conf, NULL);
1537
1538 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_nesting) < 0)
1539 return -1;
1540
1541 if (lxc_conf->lsm_aa_allow_nesting > 1)
1542 return -1;
1543
1544 return 0;
1545 }
1546
1547 static int set_config_apparmor_raw(const char *key,
1548 const char *value,
1549 struct lxc_conf *lxc_conf,
1550 void *data)
1551 {
1552 char *elem;
1553 struct lxc_list *list;
1554
1555 if (lxc_config_value_empty(value))
1556 return lxc_clear_apparmor_raw(lxc_conf);
1557
1558 list = malloc(sizeof(*list));
1559 if (!list) {
1560 errno = ENOMEM;
1561 return -1;
1562 }
1563
1564 elem = strdup(value);
1565 if (!elem) {
1566 free(list);
1567 return -1;
1568 }
1569 list->elem = elem;
1570
1571 lxc_list_add_tail(&lxc_conf->lsm_aa_raw, list);
1572
1573 return 0;
1574 }
1575
1576 static int set_config_selinux_context(const char *key, const char *value,
1577 struct lxc_conf *lxc_conf, void *data)
1578 {
1579 return set_config_string_item(&lxc_conf->lsm_se_context, value);
1580 }
1581
1582 static int set_config_selinux_context_keyring(const char *key, const char *value,
1583 struct lxc_conf *lxc_conf, void *data)
1584 {
1585 return set_config_string_item(&lxc_conf->lsm_se_keyring_context, value);
1586 }
1587
1588 static int set_config_keyring_session(const char *key, const char *value,
1589 struct lxc_conf *lxc_conf, void *data)
1590 {
1591 return set_config_bool_item(&lxc_conf->keyring_disable_session, value, false);
1592 }
1593
1594 static int set_config_log_file(const char *key, const char *value,
1595 struct lxc_conf *c, void *data)
1596 {
1597 int ret;
1598
1599 if (lxc_config_value_empty(value)) {
1600 free(c->logfile);
1601 c->logfile = NULL;
1602 return 0;
1603 }
1604
1605 /* Store these values in the lxc_conf, and then try to set for actual
1606 * current logging.
1607 */
1608 ret = set_config_path_item(&c->logfile, value);
1609 if (ret == 0)
1610 ret = lxc_log_set_file(&c->logfd, c->logfile);
1611
1612 return ret;
1613 }
1614
1615 static int set_config_log_level(const char *key, const char *value,
1616 struct lxc_conf *lxc_conf, void *data)
1617 {
1618 int newlevel;
1619
1620 if (lxc_config_value_empty(value)) {
1621 lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
1622 return 0;
1623 }
1624
1625 if (value[0] >= '0' && value[0] <= '9') {
1626 if (lxc_safe_int(value, &newlevel) < 0)
1627 return -1;
1628 } else {
1629 newlevel = lxc_log_priority_to_int(value);
1630 }
1631
1632 /* Store these values in the lxc_conf, and then try to set for actual
1633 * current logging.
1634 */
1635 lxc_conf->loglevel = newlevel;
1636
1637 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
1638 }
1639
1640 static int set_config_autodev(const char *key, const char *value,
1641 struct lxc_conf *lxc_conf, void *data)
1642 {
1643 if (lxc_config_value_empty(value)) {
1644 lxc_conf->autodev = 0;
1645 return 0;
1646 }
1647
1648 if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
1649 return -1;
1650
1651 if (lxc_conf->autodev > 1)
1652 return -1;
1653
1654 return 0;
1655 }
1656
1657 static int set_config_autodev_tmpfs_size(const char *key, const char *value,
1658 struct lxc_conf *lxc_conf, void *data)
1659 {
1660 if (lxc_config_value_empty(value)) {
1661 lxc_conf->autodevtmpfssize = 500000;
1662 return 0;
1663 }
1664
1665 if (lxc_safe_int(value, &lxc_conf->autodevtmpfssize) < 0)
1666 lxc_conf->autodevtmpfssize = 500000;
1667
1668 return 0;
1669 }
1670
1671 static int set_config_signal_halt(const char *key, const char *value,
1672 struct lxc_conf *lxc_conf, void *data)
1673 {
1674 int sig_n;
1675
1676 if (lxc_config_value_empty(value)) {
1677 lxc_conf->haltsignal = 0;
1678 return 0;
1679 }
1680
1681 sig_n = sig_parse(value);
1682 if (sig_n < 0)
1683 return -1;
1684
1685 lxc_conf->haltsignal = sig_n;
1686
1687 return 0;
1688 }
1689
1690 static int set_config_signal_reboot(const char *key, const char *value,
1691 struct lxc_conf *lxc_conf, void *data)
1692 {
1693 int sig_n;
1694
1695 if (lxc_config_value_empty(value)) {
1696 lxc_conf->rebootsignal = 0;
1697 return 0;
1698 }
1699
1700 sig_n = sig_parse(value);
1701 if (sig_n < 0)
1702 return -1;
1703
1704 lxc_conf->rebootsignal = sig_n;
1705
1706 return 0;
1707 }
1708
1709 static int set_config_signal_stop(const char *key, const char *value,
1710 struct lxc_conf *lxc_conf, void *data)
1711 {
1712 int sig_n;
1713
1714 if (lxc_config_value_empty(value)) {
1715 lxc_conf->stopsignal = 0;
1716 return 0;
1717 }
1718
1719 sig_n = sig_parse(value);
1720 if (sig_n < 0)
1721 return -1;
1722
1723 lxc_conf->stopsignal = sig_n;
1724
1725 return 0;
1726 }
1727
1728 static int __set_config_cgroup_controller(const char *key, const char *value,
1729 struct lxc_conf *lxc_conf, int version)
1730 {
1731 const char *subkey, *token;
1732 size_t token_len;
1733 struct lxc_list *cglist = NULL;
1734 struct lxc_cgroup *cgelem = NULL;
1735
1736 if (lxc_config_value_empty(value))
1737 return lxc_clear_cgroups(lxc_conf, key, version);
1738
1739 if (version == CGROUP2_SUPER_MAGIC) {
1740 token = "lxc.cgroup2.";
1741 token_len = 12;
1742 } else if (version == CGROUP_SUPER_MAGIC) {
1743 token = "lxc.cgroup.";
1744 token_len = 11;
1745 } else {
1746 return -EINVAL;
1747 }
1748
1749 if (strncmp(key, token, token_len) != 0)
1750 return -EINVAL;
1751
1752 subkey = key + token_len;
1753 if (*subkey == '\0')
1754 return -EINVAL;
1755
1756 cglist = malloc(sizeof(*cglist));
1757 if (!cglist)
1758 goto out;
1759
1760 cgelem = malloc(sizeof(*cgelem));
1761 if (!cgelem)
1762 goto out;
1763 memset(cgelem, 0, sizeof(*cgelem));
1764
1765 cgelem->subsystem = strdup(subkey);
1766 if (!cgelem->subsystem)
1767 goto out;
1768
1769 cgelem->value = strdup(value);
1770 if (!cgelem->value)
1771 goto out;
1772
1773 cgelem->version = version;
1774
1775 lxc_list_add_elem(cglist, cgelem);
1776
1777 if (version == CGROUP2_SUPER_MAGIC)
1778 lxc_list_add_tail(&lxc_conf->cgroup2, cglist);
1779 else
1780 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
1781
1782 return 0;
1783
1784 out:
1785 free(cglist);
1786 if (cgelem) {
1787 free(cgelem->subsystem);
1788 free(cgelem->value);
1789 free(cgelem);
1790 }
1791
1792 return -1;
1793 }
1794
1795 static int set_config_cgroup_controller(const char *key, const char *value,
1796 struct lxc_conf *lxc_conf, void *data)
1797 {
1798 return __set_config_cgroup_controller(key, value, lxc_conf,
1799 CGROUP_SUPER_MAGIC);
1800 }
1801
1802 static int set_config_cgroup2_controller(const char *key, const char *value,
1803 struct lxc_conf *lxc_conf, void *data)
1804 {
1805 return __set_config_cgroup_controller(key, value, lxc_conf,
1806 CGROUP2_SUPER_MAGIC);
1807 }
1808
1809
1810 static int set_config_cgroup_dir(const char *key, const char *value,
1811 struct lxc_conf *lxc_conf, void *data)
1812 {
1813 if (lxc_config_value_empty(value))
1814 return clr_config_cgroup_dir(key, lxc_conf, NULL);
1815
1816 return set_config_string_item(&lxc_conf->cgroup_meta.dir, value);
1817 }
1818
1819 static int set_config_cgroup_monitor_dir(const char *key, const char *value,
1820 struct lxc_conf *lxc_conf, void *data)
1821 {
1822 if (lxc_config_value_empty(value))
1823 return clr_config_cgroup_monitor_dir(key, lxc_conf, NULL);
1824
1825 return set_config_string_item(&lxc_conf->cgroup_meta.monitor_dir,
1826 value);
1827 }
1828
1829 static int set_config_cgroup_container_dir(const char *key, const char *value,
1830 struct lxc_conf *lxc_conf,
1831 void *data)
1832 {
1833 if (lxc_config_value_empty(value))
1834 return clr_config_cgroup_container_dir(key, lxc_conf, NULL);
1835
1836 return set_config_string_item(&lxc_conf->cgroup_meta.container_dir,
1837 value);
1838 }
1839
1840 static int set_config_cgroup_container_inner_dir(const char *key,
1841 const char *value,
1842 struct lxc_conf *lxc_conf,
1843 void *data)
1844 {
1845 if (lxc_config_value_empty(value))
1846 return clr_config_cgroup_container_inner_dir(key, lxc_conf, NULL);
1847
1848 if (strchr(value, '/') ||
1849 strcmp(value, ".") == 0 ||
1850 strcmp(value, "..") == 0)
1851 return log_error_errno(-EINVAL, EINVAL, "lxc.cgroup.dir.container.inner must be a single directory name");
1852
1853 return set_config_string_item(&lxc_conf->cgroup_meta.namespace_dir, value);
1854 }
1855
1856 static int set_config_cgroup_relative(const char *key, const char *value,
1857 struct lxc_conf *lxc_conf, void *data)
1858 {
1859 unsigned int converted;
1860 int ret;
1861
1862 if (lxc_config_value_empty(value))
1863 return clr_config_cgroup_relative(key, lxc_conf, NULL);
1864
1865 ret = lxc_safe_uint(value, &converted);
1866 if (ret < 0)
1867 return -ret;
1868
1869 if (converted == 1) {
1870 lxc_conf->cgroup_meta.relative = true;
1871 return 0;
1872 }
1873
1874 if (converted == 0) {
1875 lxc_conf->cgroup_meta.relative = false;
1876 return 0;
1877 }
1878
1879 return -EINVAL;
1880 }
1881
1882 static bool parse_limit_value(const char **value, rlim_t *res)
1883 {
1884 char *endptr = NULL;
1885
1886 if (strncmp(*value, "unlimited", STRLITERALLEN("unlimited")) == 0) {
1887 *res = RLIM_INFINITY;
1888 *value += STRLITERALLEN("unlimited");
1889 return true;
1890 }
1891
1892 errno = 0;
1893 *res = strtoull(*value, &endptr, 10);
1894 if (errno || !endptr)
1895 return false;
1896
1897 *value = endptr;
1898
1899 return true;
1900 }
1901
1902 static int set_config_prlimit(const char *key, const char *value,
1903 struct lxc_conf *lxc_conf, void *data)
1904 {
1905 struct lxc_list *iter;
1906 struct rlimit limit;
1907 rlim_t limit_value;
1908 struct lxc_list *limlist = NULL;
1909 struct lxc_limit *limelem = NULL;
1910
1911 if (lxc_config_value_empty(value))
1912 return lxc_clear_limits(lxc_conf, key);
1913
1914 if (strncmp(key, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")) != 0)
1915 return -1;
1916
1917 key += STRLITERALLEN("lxc.prlimit.");
1918
1919 /* soft limit comes first in the value */
1920 if (!parse_limit_value(&value, &limit_value))
1921 return -1;
1922
1923 limit.rlim_cur = limit_value;
1924
1925 /* skip spaces and a colon */
1926 while (isspace(*value))
1927 ++value;
1928
1929 if (*value == ':')
1930 ++value;
1931 else if (*value) /* any other character is an error here */
1932 return -1;
1933
1934 while (isspace(*value))
1935 ++value;
1936
1937 /* optional hard limit */
1938 if (*value) {
1939 if (!parse_limit_value(&value, &limit_value))
1940 return -1;
1941
1942 limit.rlim_max = limit_value;
1943
1944 /* check for trailing garbage */
1945 while (isspace(*value))
1946 ++value;
1947
1948 if (*value)
1949 return -1;
1950 } else {
1951 /* a single value sets both hard and soft limit */
1952 limit.rlim_max = limit.rlim_cur;
1953 }
1954
1955 /* find existing list element */
1956 lxc_list_for_each(iter, &lxc_conf->limits) {
1957 limelem = iter->elem;
1958 if (!strcmp(key, limelem->resource)) {
1959 limelem->limit = limit;
1960 return 0;
1961 }
1962 }
1963
1964 /* allocate list element */
1965 limlist = malloc(sizeof(*limlist));
1966 if (!limlist)
1967 goto on_error;
1968
1969 limelem = malloc(sizeof(*limelem));
1970 if (!limelem)
1971 goto on_error;
1972 memset(limelem, 0, sizeof(*limelem));
1973
1974 limelem->resource = strdup(key);
1975 if (!limelem->resource)
1976 goto on_error;
1977
1978 limelem->limit = limit;
1979 lxc_list_add_elem(limlist, limelem);;
1980 lxc_list_add_tail(&lxc_conf->limits, limlist);
1981
1982 return 0;
1983
1984 on_error:
1985 free(limlist);
1986
1987 if (limelem) {
1988 free(limelem->resource);
1989 free(limelem);
1990 }
1991
1992 return -1;
1993 }
1994
1995 static int set_config_sysctl(const char *key, const char *value,
1996 struct lxc_conf *lxc_conf, void *data)
1997 {
1998 struct lxc_list *iter;
1999 char *replace_value = NULL;
2000 struct lxc_list *sysctl_list = NULL;
2001 struct lxc_sysctl *sysctl_elem = NULL;
2002
2003 if (lxc_config_value_empty(value))
2004 return clr_config_sysctl(key, lxc_conf, NULL);
2005
2006 if (strncmp(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")) != 0)
2007 return -1;
2008
2009 key += STRLITERALLEN("lxc.sysctl.");
2010
2011 /* find existing list element */
2012 lxc_list_for_each(iter, &lxc_conf->sysctls) {
2013 sysctl_elem = iter->elem;
2014
2015 if (strcmp(key, sysctl_elem->key) != 0)
2016 continue;
2017
2018 replace_value = strdup(value);
2019 if (!replace_value)
2020 return -1;
2021
2022 free(sysctl_elem->value);
2023 sysctl_elem->value = replace_value;
2024
2025 return 0;
2026 }
2027
2028 /* allocate list element */
2029 sysctl_list = malloc(sizeof(*sysctl_list));
2030 if (!sysctl_list)
2031 goto on_error;
2032
2033 sysctl_elem = malloc(sizeof(*sysctl_elem));
2034 if (!sysctl_elem)
2035 goto on_error;
2036 memset(sysctl_elem, 0, sizeof(*sysctl_elem));
2037
2038 sysctl_elem->key = strdup(key);
2039 if (!sysctl_elem->key)
2040 goto on_error;
2041
2042 sysctl_elem->value = strdup(value);
2043 if (!sysctl_elem->value)
2044 goto on_error;
2045
2046 lxc_list_add_elem(sysctl_list, sysctl_elem);
2047 lxc_list_add_tail(&lxc_conf->sysctls, sysctl_list);
2048
2049 return 0;
2050
2051 on_error:
2052 free(sysctl_list);
2053
2054 if (sysctl_elem) {
2055 free(sysctl_elem->key);
2056 free(sysctl_elem->value);
2057 free(sysctl_elem);
2058 }
2059
2060 return -1;
2061 }
2062
2063 static int set_config_proc(const char *key, const char *value,
2064 struct lxc_conf *lxc_conf, void *data)
2065 {
2066 const char *subkey;
2067 struct lxc_list *proclist = NULL;
2068 struct lxc_proc *procelem = NULL;
2069
2070 if (lxc_config_value_empty(value))
2071 return clr_config_proc(key, lxc_conf, NULL);
2072
2073 if (strncmp(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")) != 0)
2074 return -1;
2075
2076 subkey = key + STRLITERALLEN("lxc.proc.");
2077 if (*subkey == '\0')
2078 return -EINVAL;
2079
2080 proclist = malloc(sizeof(*proclist));
2081 if (!proclist)
2082 goto on_error;
2083
2084 procelem = malloc(sizeof(*procelem));
2085 if (!procelem)
2086 goto on_error;
2087 memset(procelem, 0, sizeof(*procelem));
2088
2089 procelem->filename = strdup(subkey);
2090 procelem->value = strdup(value);
2091
2092 if (!procelem->filename || !procelem->value)
2093 goto on_error;
2094
2095 proclist->elem = procelem;
2096
2097 lxc_list_add_tail(&lxc_conf->procs, proclist);
2098
2099 return 0;
2100
2101 on_error:
2102 free(proclist);
2103
2104 if (procelem) {
2105 free(procelem->filename);
2106 free(procelem->value);
2107 free(procelem);
2108 }
2109
2110 return -1;
2111 }
2112
2113 static int set_config_idmaps(const char *key, const char *value,
2114 struct lxc_conf *lxc_conf, void *data)
2115 {
2116 unsigned long hostid, nsid, range;
2117 char type;
2118 int ret;
2119 struct lxc_list *idmaplist = NULL;
2120 struct id_map *idmap = NULL;
2121
2122 if (lxc_config_value_empty(value))
2123 return lxc_clear_idmaps(lxc_conf);
2124
2125 idmaplist = malloc(sizeof(*idmaplist));
2126 if (!idmaplist)
2127 goto on_error;
2128
2129 idmap = malloc(sizeof(*idmap));
2130 if (!idmap)
2131 goto on_error;
2132 memset(idmap, 0, sizeof(*idmap));
2133
2134 ret = parse_idmaps(value, &type, &nsid, &hostid, &range);
2135 if (ret < 0) {
2136 ERROR("Failed to parse id mappings");
2137 goto on_error;
2138 }
2139
2140 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
2141 if (type == 'u')
2142 idmap->idtype = ID_TYPE_UID;
2143 else if (type == 'g')
2144 idmap->idtype = ID_TYPE_GID;
2145 else
2146 goto on_error;
2147
2148 idmap->hostid = hostid;
2149 idmap->nsid = nsid;
2150 idmap->range = range;
2151 idmaplist->elem = idmap;
2152 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
2153
2154 if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID)
2155 if (idmap->nsid == 0)
2156 lxc_conf->root_nsuid_map = idmap;
2157
2158 if (!lxc_conf->root_nsgid_map && idmap->idtype == ID_TYPE_GID)
2159 if (idmap->nsid == 0)
2160 lxc_conf->root_nsgid_map = idmap;
2161
2162 idmap = NULL;
2163
2164 return 0;
2165
2166 on_error:
2167 free(idmaplist);
2168 free(idmap);
2169
2170 return -1;
2171 }
2172
2173 static int set_config_mount_fstab(const char *key, const char *value,
2174 struct lxc_conf *lxc_conf, void *data)
2175 {
2176 if (lxc_config_value_empty(value)) {
2177 clr_config_mount_fstab(key, lxc_conf, NULL);
2178 return -1;
2179 }
2180
2181 return set_config_path_item(&lxc_conf->fstab, value);
2182 }
2183
2184 static int set_config_mount_auto(const char *key, const char *value,
2185 struct lxc_conf *lxc_conf, void *data)
2186 {
2187 char *autos, *token;
2188 int i;
2189 int ret = -1;
2190 static struct {
2191 const char *token;
2192 int mask;
2193 int flag;
2194 } allowed_auto_mounts[] = {
2195 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2196 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2197 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
2198 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2199 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
2200 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2201 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
2202 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
2203 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
2204 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
2205 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
2206 { "cgroup:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC | LXC_AUTO_CGROUP_FORCE },
2207 { "cgroup:mixed:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED | LXC_AUTO_CGROUP_FORCE },
2208 { "cgroup:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO | LXC_AUTO_CGROUP_FORCE },
2209 { "cgroup:rw:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW | LXC_AUTO_CGROUP_FORCE },
2210 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
2211 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
2212 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
2213 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
2214 { "cgroup-full:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC | LXC_AUTO_CGROUP_FORCE },
2215 { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED | LXC_AUTO_CGROUP_FORCE },
2216 { "cgroup-full:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO | LXC_AUTO_CGROUP_FORCE },
2217 { "cgroup-full:rw:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW | LXC_AUTO_CGROUP_FORCE },
2218 { "shmounts:", LXC_AUTO_SHMOUNTS_MASK, LXC_AUTO_SHMOUNTS },
2219 /* For adding anything that is just a single on/off, but has no
2220 * options: keep mask and flag identical and just define the enum
2221 * value as an unused bit so far
2222 */
2223 { NULL, 0, 0 }
2224 };
2225
2226 if (lxc_config_value_empty(value)) {
2227 lxc_conf->auto_mounts = 0;
2228 return 0;
2229 }
2230
2231 autos = strdup(value);
2232 if (!autos)
2233 return -1;
2234
2235 lxc_iterate_parts(token, autos, " \t") {
2236 bool is_shmounts = false;
2237
2238 for (i = 0; allowed_auto_mounts[i].token; i++) {
2239 if (!strcmp(allowed_auto_mounts[i].token, token))
2240 break;
2241
2242 if (strcmp("shmounts:", allowed_auto_mounts[i].token) == 0 &&
2243 strncmp("shmounts:", token, STRLITERALLEN("shmounts:")) == 0) {
2244 is_shmounts = true;
2245 break;
2246 }
2247 }
2248
2249 if (!allowed_auto_mounts[i].token) {
2250 ERROR("Invalid filesystem to automount \"%s\"", token);
2251 goto on_error;
2252 }
2253
2254 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
2255 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
2256
2257 if (is_shmounts) {
2258 char *container_path;
2259 char *host_path;
2260
2261 host_path = token + STRLITERALLEN("shmounts:");
2262 if (*host_path == '\0') {
2263 SYSERROR("Failed to copy shmounts host path");
2264 goto on_error;
2265 }
2266
2267 container_path = strchr(host_path, ':');
2268 if (!container_path || *(container_path + 1) == '\0')
2269 container_path = "/dev/.lxc-mounts";
2270 else
2271 *container_path++ = '\0';
2272
2273 lxc_conf->shmount.path_host = strdup(host_path);
2274 if (!lxc_conf->shmount.path_host) {
2275 SYSERROR("Failed to copy shmounts host path");
2276 goto on_error;
2277 }
2278
2279 lxc_conf->shmount.path_cont = strdup(container_path);
2280 if(!lxc_conf->shmount.path_cont) {
2281 SYSERROR("Failed to copy shmounts container path");
2282 goto on_error;
2283 }
2284 }
2285 }
2286
2287 ret = 0;
2288
2289 on_error:
2290 free(autos);
2291
2292 return ret;
2293 }
2294
2295 static int set_config_mount(const char *key, const char *value,
2296 struct lxc_conf *lxc_conf, void *data)
2297 {
2298 char *mntelem;
2299 struct lxc_list *mntlist;
2300
2301 if (lxc_config_value_empty(value))
2302 return lxc_clear_mount_entries(lxc_conf);
2303
2304 mntlist = malloc(sizeof(*mntlist));
2305 if (!mntlist)
2306 return -1;
2307
2308 mntelem = strdup(value);
2309 if (!mntelem) {
2310 free(mntlist);
2311 return -1;
2312 }
2313 mntlist->elem = mntelem;
2314
2315 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
2316
2317 return 0;
2318 }
2319
2320 int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) {
2321 return set_config_mount(NULL, value, lxc_conf, NULL);
2322 }
2323
2324 static int set_config_cap_keep(const char *key, const char *value,
2325 struct lxc_conf *lxc_conf, void *data)
2326 {
2327 char *keepcaps, *token;
2328 struct lxc_list *keeplist;
2329 int ret = -1;
2330
2331 if (lxc_config_value_empty(value))
2332 return lxc_clear_config_keepcaps(lxc_conf);
2333
2334 keepcaps = strdup(value);
2335 if (!keepcaps)
2336 return -1;
2337
2338 /* In case several capability keep is specified in a single line
2339 * split these caps in a single element for the list.
2340 */
2341 lxc_iterate_parts(token, keepcaps, " \t") {
2342 if (!strcmp(token, "none"))
2343 lxc_clear_config_keepcaps(lxc_conf);
2344
2345 keeplist = malloc(sizeof(*keeplist));
2346 if (!keeplist)
2347 goto on_error;
2348
2349 keeplist->elem = strdup(token);
2350 if (!keeplist->elem) {
2351 free(keeplist);
2352 goto on_error;
2353 }
2354
2355 lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
2356 }
2357
2358 ret = 0;
2359
2360 on_error:
2361 free(keepcaps);
2362
2363 return ret;
2364 }
2365
2366 static int set_config_cap_drop(const char *key, const char *value,
2367 struct lxc_conf *lxc_conf, void *data)
2368 {
2369 char *dropcaps, *token;
2370 struct lxc_list *droplist;
2371 int ret = -1;
2372
2373 if (lxc_config_value_empty(value))
2374 return lxc_clear_config_caps(lxc_conf);
2375
2376 dropcaps = strdup(value);
2377 if (!dropcaps)
2378 return -1;
2379
2380 /* In case several capability drop is specified in a single line
2381 * split these caps in a single element for the list.
2382 */
2383 lxc_iterate_parts(token, dropcaps, " \t") {
2384 droplist = malloc(sizeof(*droplist));
2385 if (!droplist)
2386 goto on_error;
2387
2388 droplist->elem = strdup(token);
2389 if (!droplist->elem) {
2390 free(droplist);
2391 goto on_error;
2392 }
2393
2394 lxc_list_add_tail(&lxc_conf->caps, droplist);
2395 }
2396
2397 ret = 0;
2398
2399 on_error:
2400 free(dropcaps);
2401
2402 return ret;
2403 }
2404
2405 static int set_config_console_path(const char *key, const char *value,
2406 struct lxc_conf *lxc_conf, void *data)
2407 {
2408 return set_config_path_item(&lxc_conf->console.path, value);
2409 }
2410
2411 static int set_config_console_rotate(const char *key, const char *value,
2412 struct lxc_conf *lxc_conf, void *data)
2413 {
2414 if (lxc_config_value_empty(value)) {
2415 lxc_conf->console.log_rotate = 0;
2416 return 0;
2417 }
2418
2419 if (lxc_safe_uint(value, &lxc_conf->console.log_rotate) < 0)
2420 return -1;
2421
2422 if (lxc_conf->console.log_rotate > 1) {
2423 ERROR("The \"lxc.console.rotate\" config key can only be set "
2424 "to 0 or 1");
2425 return -1;
2426 }
2427
2428 return 0;
2429 }
2430
2431 static int set_config_console_logfile(const char *key, const char *value,
2432 struct lxc_conf *lxc_conf, void *data)
2433 {
2434 return set_config_path_item(&lxc_conf->console.log_path, value);
2435 }
2436
2437 static int set_config_console_buffer_size(const char *key, const char *value,
2438 struct lxc_conf *lxc_conf, void *data)
2439 {
2440 int ret;
2441 int64_t size;
2442 uint64_t buffer_size, pgsz;
2443
2444 if (lxc_config_value_empty(value)) {
2445 lxc_conf->console.buffer_size = 0;
2446 return 0;
2447 }
2448
2449 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2450 if (!strcmp(value, "auto")) {
2451 lxc_conf->console.buffer_size = 1 << 17;
2452 return 0;
2453 }
2454
2455 ret = parse_byte_size_string(value, &size);
2456 if (ret < 0)
2457 return -1;
2458
2459 if (size < 0)
2460 return -EINVAL;
2461
2462 /* must be at least a page size */
2463 pgsz = lxc_getpagesize();
2464 if ((uint64_t)size < pgsz) {
2465 NOTICE("Requested ringbuffer size for the console is %" PRId64
2466 " but must be at least %" PRId64
2467 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
2468 size, pgsz, pgsz);
2469 size = pgsz;
2470 }
2471
2472 buffer_size = lxc_find_next_power2((uint64_t)size);
2473 if (buffer_size == 0)
2474 return -EINVAL;
2475
2476 if (buffer_size != size)
2477 NOTICE("Passed size was not a power of 2. Rounding log size to "
2478 "next power of two: %" PRIu64 " bytes", buffer_size);
2479
2480 lxc_conf->console.buffer_size = buffer_size;
2481
2482 return 0;
2483 }
2484
2485 static int set_config_console_size(const char *key, const char *value,
2486 struct lxc_conf *lxc_conf, void *data)
2487 {
2488 int ret;
2489 int64_t size;
2490 uint64_t log_size, pgsz;
2491
2492 if (lxc_config_value_empty(value)) {
2493 lxc_conf->console.log_size = 0;
2494 return 0;
2495 }
2496
2497 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2498 if (!strcmp(value, "auto")) {
2499 lxc_conf->console.log_size = 1 << 17;
2500 return 0;
2501 }
2502
2503 ret = parse_byte_size_string(value, &size);
2504 if (ret < 0)
2505 return -1;
2506
2507 if (size < 0)
2508 return -EINVAL;
2509
2510 /* must be at least a page size */
2511 pgsz = lxc_getpagesize();
2512 if ((uint64_t)size < pgsz) {
2513 NOTICE("Requested ringbuffer size for the console is %" PRId64
2514 " but must be at least %" PRId64
2515 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
2516 size, pgsz, pgsz);
2517 size = pgsz;
2518 }
2519
2520 log_size = lxc_find_next_power2((uint64_t)size);
2521 if (log_size == 0)
2522 return -EINVAL;
2523
2524 if (log_size != size)
2525 NOTICE("Passed size was not a power of 2. Rounding log size to "
2526 "next power of two: %" PRIu64 " bytes", log_size);
2527
2528 lxc_conf->console.log_size = log_size;
2529
2530 return 0;
2531 }
2532
2533 /*
2534 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
2535 * file, we expand it in the unexpanded_config, so that after a save_config we
2536 * store the hwaddr for re-use.
2537 * This is only called when reading the config file, not when executing a
2538 * lxc.include.
2539 * 'x' and 'X' are substituted in-place.
2540 */
2541 static void update_hwaddr(const char *line)
2542 {
2543 char *p;
2544
2545 line += lxc_char_left_gc(line, strlen(line));
2546 if (line[0] == '#')
2547 return;
2548
2549 if (!lxc_config_net_is_hwaddr(line))
2550 return;
2551
2552 /* Let config_net_hwaddr raise the error. */
2553 p = strchr(line, '=');
2554 if (!p)
2555 return;
2556 p++;
2557
2558 while (isblank(*p))
2559 p++;
2560
2561 if (!*p)
2562 return;
2563
2564 rand_complete_hwaddr(p);
2565 }
2566
2567 int append_unexp_config_line(const char *line, struct lxc_conf *conf)
2568 {
2569 size_t linelen;
2570 size_t len = conf->unexpanded_len;
2571
2572 update_hwaddr(line);
2573
2574 linelen = strlen(line);
2575 while (conf->unexpanded_alloced <= len + linelen + 2) {
2576 char *tmp = realloc(conf->unexpanded_config,
2577 conf->unexpanded_alloced + 1024);
2578 if (!tmp)
2579 return -1;
2580
2581 if (!conf->unexpanded_config)
2582 *tmp = '\0';
2583
2584 conf->unexpanded_config = tmp;
2585 conf->unexpanded_alloced += 1024;
2586 }
2587
2588 memcpy(conf->unexpanded_config + conf->unexpanded_len, line, linelen);
2589 conf->unexpanded_len += linelen;
2590 if (line[linelen - 1] != '\n')
2591 conf->unexpanded_config[conf->unexpanded_len++] = '\n';
2592 conf->unexpanded_config[conf->unexpanded_len] = '\0';
2593
2594 return 0;
2595 }
2596
2597 static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2598 {
2599 __do_closedir DIR *dir = NULL;
2600 struct dirent *direntp;
2601 char path[PATH_MAX];
2602 int len;
2603 int ret = -1;
2604
2605 dir = opendir(dirp);
2606 if (!dir)
2607 return -1;
2608
2609 while ((direntp = readdir(dir))) {
2610 const char *fnam;
2611
2612 fnam = direntp->d_name;
2613 if (!strcmp(fnam, "."))
2614 continue;
2615
2616 if (!strcmp(fnam, ".."))
2617 continue;
2618
2619 len = strlen(fnam);
2620 if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
2621 continue;
2622
2623 len = snprintf(path, PATH_MAX, "%s/%s", dirp, fnam);
2624 if (len < 0 || len >= PATH_MAX)
2625 return -1;
2626
2627 ret = lxc_config_read(path, lxc_conf, true);
2628 if (ret < 0)
2629 return -1;
2630 }
2631
2632 return 0;
2633 }
2634
2635 static int set_config_includefiles(const char *key, const char *value,
2636 struct lxc_conf *lxc_conf, void *data)
2637 {
2638 if (lxc_config_value_empty(value)) {
2639 clr_config_includefiles(key, lxc_conf, NULL);
2640 return 0;
2641 }
2642
2643 if (is_dir(value))
2644 return do_includedir(value, lxc_conf);
2645
2646 return lxc_config_read(value, lxc_conf, true);
2647 }
2648
2649 static int set_config_rootfs_path(const char *key, const char *value,
2650 struct lxc_conf *lxc_conf, void *data)
2651 {
2652 int ret;
2653 char *dup, *tmp;
2654 const char *container_path;
2655
2656 if (lxc_config_value_empty(value)) {
2657 free(lxc_conf->rootfs.path);
2658 lxc_conf->rootfs.path = NULL;
2659 return 0;
2660 }
2661
2662 dup = strdup(value);
2663 if (!dup)
2664 return -1;
2665
2666 /* Split <storage type>:<container path> into <storage type> and
2667 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2668 * "rootfs.path" to <container path>.
2669 */
2670 tmp = strchr(dup, ':');
2671 if (tmp) {
2672 *tmp = '\0';
2673
2674 ret = set_config_path_item(&lxc_conf->rootfs.bdev_type, dup);
2675 if (ret < 0) {
2676 free(dup);
2677 return -1;
2678 }
2679
2680 tmp++;
2681 container_path = tmp;
2682 } else {
2683 container_path = value;
2684 }
2685
2686 ret = set_config_path_item(&lxc_conf->rootfs.path, container_path);
2687 free(dup);
2688
2689 return ret;
2690 }
2691
2692 static int set_config_rootfs_managed(const char *key, const char *value,
2693 struct lxc_conf *lxc_conf, void *data)
2694 {
2695 return set_config_bool_item(&lxc_conf->rootfs.managed, value, true);
2696 }
2697
2698 static int set_config_rootfs_mount(const char *key, const char *value,
2699 struct lxc_conf *lxc_conf, void *data)
2700 {
2701 return set_config_path_item(&lxc_conf->rootfs.mount, value);
2702 }
2703
2704 static int set_config_rootfs_options(const char *key, const char *value,
2705 struct lxc_conf *lxc_conf, void *data)
2706 {
2707 unsigned long mflags = 0, pflags = 0;
2708 char *mdata = NULL, *opts = NULL;
2709 int ret;
2710 struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
2711
2712 ret = parse_mntopts(value, &mflags, &mdata);
2713 if (ret < 0)
2714 return -EINVAL;
2715
2716 ret = parse_propagationopts(value, &pflags);
2717 if (ret < 0) {
2718 free(mdata);
2719 return -EINVAL;
2720 }
2721
2722 ret = set_config_string_item(&opts, value);
2723 if (ret < 0) {
2724 free(mdata);
2725 return -ENOMEM;
2726 }
2727
2728 rootfs->mountflags = mflags | pflags;
2729 rootfs->options = opts;
2730 rootfs->data = mdata;
2731
2732 return 0;
2733 }
2734
2735 static int set_config_uts_name(const char *key, const char *value,
2736 struct lxc_conf *lxc_conf, void *data)
2737 {
2738 struct utsname *utsname;
2739
2740 if (lxc_config_value_empty(value)) {
2741 clr_config_uts_name(key, lxc_conf, NULL);
2742 return 0;
2743 }
2744
2745 utsname = malloc(sizeof(*utsname));
2746 if (!utsname)
2747 return -1;
2748
2749 if (strlen(value) >= sizeof(utsname->nodename)) {
2750 free(utsname);
2751 return -1;
2752 }
2753
2754 (void)strlcpy(utsname->nodename, value, sizeof(utsname->nodename));
2755 free(lxc_conf->utsname);
2756 lxc_conf->utsname = utsname;
2757
2758 return 0;
2759 }
2760
2761 static int set_config_namespace_clone(const char *key, const char *value,
2762 struct lxc_conf *lxc_conf, void *data)
2763 {
2764 char *ns, *token;
2765 int cloneflag = 0;
2766
2767 if (lxc_config_value_empty(value))
2768 return clr_config_namespace_clone(key, lxc_conf, data);
2769
2770 if (lxc_conf->ns_keep != 0) {
2771 errno = EINVAL;
2772 SYSERROR("Cannot set both \"lxc.namespace.clone\" and "
2773 "\"lxc.namespace.keep\"");
2774 return -EINVAL;
2775 }
2776
2777 ns = strdup(value);
2778 if (!ns)
2779 return -1;
2780
2781 lxc_iterate_parts(token, ns, " \t") {
2782 token += lxc_char_left_gc(token, strlen(token));
2783 token[lxc_char_right_gc(token, strlen(token))] = '\0';
2784 cloneflag = lxc_namespace_2_cloneflag(token);
2785 if (cloneflag < 0) {
2786 free(ns);
2787 return -EINVAL;
2788 }
2789 lxc_conf->ns_clone |= cloneflag;
2790 }
2791 free(ns);
2792
2793 return 0;
2794 }
2795
2796 static int set_config_namespace_keep(const char *key, const char *value,
2797 struct lxc_conf *lxc_conf, void *data)
2798 {
2799 char *ns, *token;
2800 int cloneflag = 0;
2801
2802 if (lxc_config_value_empty(value))
2803 return clr_config_namespace_keep(key, lxc_conf, data);
2804
2805 if (lxc_conf->ns_clone != 0) {
2806 errno = EINVAL;
2807 SYSERROR("Cannot set both \"lxc.namespace.clone\" and "
2808 "\"lxc.namespace.keep\"");
2809 return -EINVAL;
2810 }
2811
2812 ns = strdup(value);
2813 if (!ns)
2814 return -1;
2815
2816 lxc_iterate_parts(token, ns, " \t") {
2817 token += lxc_char_left_gc(token, strlen(token));
2818 token[lxc_char_right_gc(token, strlen(token))] = '\0';
2819 cloneflag = lxc_namespace_2_cloneflag(token);
2820 if (cloneflag < 0) {
2821 free(ns);
2822 return -EINVAL;
2823 }
2824 lxc_conf->ns_keep |= cloneflag;
2825 }
2826 free(ns);
2827
2828 return 0;
2829 }
2830
2831 static int set_config_time_offset_boot(const char *key, const char *value,
2832 struct lxc_conf *lxc_conf, void *data)
2833 {
2834 int ret;
2835 char *unit;
2836 int64_t offset = 0;
2837 char buf[STRLITERALLEN("ms") + 1];
2838
2839 if (lxc_config_value_empty(value))
2840 return clr_config_time_offset_boot(key, lxc_conf, data);
2841
2842 ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
2843 if (ret)
2844 return ret;
2845
2846 unit = lxc_trim_whitespace_in_place(buf);
2847 if (strcmp(unit, "h") == 0) {
2848 if (!multiply_overflow(offset, 3600, &lxc_conf->timens.s_boot))
2849 return -EOVERFLOW;
2850 } else if (strcmp(unit, "m") == 0) {
2851 if (!multiply_overflow(offset, 60, &lxc_conf->timens.s_boot))
2852 return -EOVERFLOW;
2853 } else if (strcmp(unit, "s") == 0) {
2854 lxc_conf->timens.s_boot = offset;
2855 } else if (strcmp(unit, "ms") == 0) {
2856 if (!multiply_overflow(offset, 1000000, &lxc_conf->timens.ns_boot))
2857 return -EOVERFLOW;
2858 } else if (strcmp(unit, "us") == 0) {
2859 if (!multiply_overflow(offset, 1000, &lxc_conf->timens.ns_boot))
2860 return -EOVERFLOW;
2861 } else if (strcmp(unit, "ns") == 0) {
2862 lxc_conf->timens.ns_boot = offset;
2863 } else {
2864 return ret_errno(EINVAL);
2865 }
2866
2867 return 0;
2868 }
2869
2870 static int set_config_time_offset_monotonic(const char *key, const char *value,
2871 struct lxc_conf *lxc_conf, void *data)
2872 {
2873 int ret;
2874 char *unit;
2875 int64_t offset = 0;
2876 char buf[STRLITERALLEN("ms") + 1];
2877
2878 if (lxc_config_value_empty(value))
2879 return clr_config_time_offset_monotonic(key, lxc_conf, data);
2880
2881 ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
2882 if (ret)
2883 return ret;
2884
2885 unit = lxc_trim_whitespace_in_place(buf);
2886 if (strcmp(unit, "h") == 0) {
2887 if (!multiply_overflow(offset, 3600, &lxc_conf->timens.s_monotonic))
2888 return -EOVERFLOW;
2889 } else if (strcmp(unit, "m") == 0) {
2890 if (!multiply_overflow(offset, 60, &lxc_conf->timens.s_monotonic))
2891 return -EOVERFLOW;
2892 } else if (strcmp(unit, "s") == 0) {
2893 lxc_conf->timens.s_monotonic = offset;
2894 } else if (strcmp(unit, "ms") == 0) {
2895 if (!multiply_overflow(offset, 1000000, &lxc_conf->timens.ns_monotonic))
2896 return -EOVERFLOW;
2897 } else if (strcmp(unit, "us") == 0) {
2898 if (!multiply_overflow(offset, 1000, &lxc_conf->timens.ns_monotonic))
2899 return -EOVERFLOW;
2900 } else if (strcmp(unit, "ns") == 0) {
2901 lxc_conf->timens.ns_monotonic = offset;
2902 } else {
2903 return ret_errno(EINVAL);
2904 }
2905
2906 return 0;
2907 }
2908
2909 static int set_config_namespace_share(const char *key, const char *value,
2910 struct lxc_conf *lxc_conf, void *data)
2911 {
2912 int ns_idx;
2913 const char *namespace;
2914
2915 if (lxc_config_value_empty(value))
2916 return clr_config_namespace_share(key, lxc_conf, data);
2917
2918 namespace = key + STRLITERALLEN("lxc.namespace.share.");
2919 ns_idx = lxc_namespace_2_ns_idx(namespace);
2920 if (ns_idx < 0)
2921 return ns_idx;
2922
2923 return set_config_string_item(&lxc_conf->ns_share[ns_idx], value);
2924 }
2925
2926 struct parse_line_conf {
2927 struct lxc_conf *conf;
2928 bool from_include;
2929 };
2930
2931 static int parse_line(char *buffer, void *data)
2932 {
2933 char *dot, *key, *line, *linep, *value;
2934 bool empty_line;
2935 struct lxc_config_t *config;
2936 int ret = 0;
2937 char *dup = buffer;
2938 struct parse_line_conf *plc = data;
2939
2940 /* If there are newlines in the config file we should keep them. */
2941 empty_line = lxc_is_line_empty(dup);
2942 if (empty_line)
2943 dup = "\n";
2944
2945 /* We have to dup the buffer otherwise, at the re-exec for reboot we
2946 * modified the original string on the stack by replacing '=' by '\0'
2947 * below.
2948 */
2949 linep = line = strdup(dup);
2950 if (!line)
2951 return -1;
2952
2953 if (!plc->from_include) {
2954 ret = append_unexp_config_line(line, plc->conf);
2955 if (ret < 0)
2956 goto on_error;
2957 }
2958
2959 if (empty_line)
2960 goto on_error;
2961
2962 line += lxc_char_left_gc(line, strlen(line));
2963
2964 /* ignore comments */
2965 if (line[0] == '#')
2966 goto on_error;
2967
2968 /* martian option - don't add it to the config itself */
2969 if (strncmp(line, "lxc.", 4))
2970 goto on_error;
2971
2972 ret = -1;
2973
2974 dot = strchr(line, '=');
2975 if (!dot) {
2976 ERROR("Invalid configuration line: %s", line);
2977 goto on_error;
2978 }
2979
2980 *dot = '\0';
2981 value = dot + 1;
2982
2983 key = line;
2984 key[lxc_char_right_gc(key, strlen(key))] = '\0';
2985
2986 value += lxc_char_left_gc(value, strlen(value));
2987 value[lxc_char_right_gc(value, strlen(value))] = '\0';
2988
2989 if (*value == '\'' || *value == '\"') {
2990 size_t len;
2991
2992 len = strlen(value);
2993 if (len > 1 && value[len - 1] == *value) {
2994 value[len - 1] = '\0';
2995 value++;
2996 }
2997 }
2998
2999 config = lxc_get_config(key);
3000 if (!config) {
3001 ERROR("Unknown configuration key \"%s\"", key);
3002 goto on_error;
3003 }
3004
3005 ret = config->set(key, value, plc->conf, NULL);
3006
3007 on_error:
3008 free(linep);
3009
3010 return ret;
3011 }
3012
3013 static struct new_config_item *parse_new_conf_line(char *buffer)
3014 {
3015 char *dot, *key, *line, *linep, *value;
3016 int ret = 0;
3017 char *dup = buffer;
3018 struct new_config_item *new = NULL;
3019
3020 linep = line = strdup(dup);
3021 if (!line)
3022 return NULL;
3023
3024 line += lxc_char_left_gc(line, strlen(line));
3025
3026 /* martian option - don't add it to the config itself */
3027 if (strncmp(line, "lxc.", 4))
3028 goto on_error;
3029
3030 ret = -1;
3031 dot = strchr(line, '=');
3032 if (!dot) {
3033 ERROR("Invalid configuration item: %s", line);
3034 goto on_error;
3035 }
3036
3037 *dot = '\0';
3038 value = dot + 1;
3039
3040 key = line;
3041 key[lxc_char_right_gc(key, strlen(key))] = '\0';
3042
3043 value += lxc_char_left_gc(value, strlen(value));
3044 value[lxc_char_right_gc(value, strlen(value))] = '\0';
3045
3046 if (*value == '\'' || *value == '\"') {
3047 size_t len;
3048
3049 len = strlen(value);
3050 if (len > 1 && value[len - 1] == *value) {
3051 value[len - 1] = '\0';
3052 value++;
3053 }
3054 }
3055
3056 ret = -1;
3057 new = malloc(sizeof(struct new_config_item));
3058 if (!new)
3059 goto on_error;
3060
3061 new->key = strdup(key);
3062 new->val = strdup(value);
3063 if (!new->val || !new->key)
3064 goto on_error;
3065
3066 ret = 0;
3067
3068 on_error:
3069 free(linep);
3070
3071 if (ret < 0 && new) {
3072 free(new->key);
3073 free(new->val);
3074 free(new);
3075 new = NULL;
3076 }
3077
3078 return new;
3079 }
3080
3081 int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
3082 {
3083 struct parse_line_conf c;
3084
3085 c.conf = conf;
3086 c.from_include = from_include;
3087
3088 /* Catch only the top level config file name in the structure. */
3089 if (!conf->rcfile)
3090 conf->rcfile = strdup(file);
3091
3092 return lxc_file_for_each_line_mmap(file, parse_line, &c);
3093 }
3094
3095 int lxc_config_define_add(struct lxc_list *defines, char *arg)
3096 {
3097 struct lxc_list *dent;
3098
3099 dent = malloc(sizeof(struct lxc_list));
3100 if (!dent)
3101 return -1;
3102
3103 dent->elem = parse_new_conf_line(arg);
3104 if (!dent->elem) {
3105 free(dent);
3106 return -1;
3107 }
3108
3109 lxc_list_add_tail(defines, dent);
3110
3111 return 0;
3112 }
3113
3114 bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c)
3115 {
3116 struct lxc_list *it;
3117 bool bret = true;
3118
3119 lxc_list_for_each(it, defines) {
3120 struct new_config_item *new_item = it->elem;
3121 bret = c->set_config_item(c, new_item->key, new_item->val);
3122 if (!bret)
3123 break;
3124 }
3125
3126 lxc_config_define_free(defines);
3127
3128 return bret;
3129 }
3130
3131 void lxc_config_define_free(struct lxc_list *defines)
3132 {
3133 struct lxc_list *it, *next;
3134
3135 lxc_list_for_each_safe(it, defines, next) {
3136 struct new_config_item *new_item = it->elem;
3137 free(new_item->key);
3138 free(new_item->val);
3139 lxc_list_del(it);
3140 free(it);
3141 }
3142 }
3143
3144 signed long lxc_config_parse_arch(const char *arch)
3145 {
3146 #if HAVE_SYS_PERSONALITY_H
3147 size_t i;
3148 struct per_name {
3149 char *name;
3150 unsigned long per;
3151 } pername[] = {
3152 { "arm", PER_LINUX32 },
3153 { "armel", PER_LINUX32 },
3154 { "armhf", PER_LINUX32 },
3155 { "armv7l", PER_LINUX32 },
3156 { "athlon", PER_LINUX32 },
3157 { "i386", PER_LINUX32 },
3158 { "i486", PER_LINUX32 },
3159 { "i586", PER_LINUX32 },
3160 { "i686", PER_LINUX32 },
3161 { "linux32", PER_LINUX32 },
3162 { "mips", PER_LINUX32 },
3163 { "mipsel", PER_LINUX32 },
3164 { "ppc", PER_LINUX32 },
3165 { "powerpc", PER_LINUX32 },
3166 { "x86", PER_LINUX32 },
3167 { "amd64", PER_LINUX },
3168 { "arm64", PER_LINUX },
3169 { "linux64", PER_LINUX },
3170 { "mips64", PER_LINUX },
3171 { "mips64el", PER_LINUX },
3172 { "ppc64", PER_LINUX },
3173 { "ppc64el", PER_LINUX },
3174 { "ppc64le", PER_LINUX },
3175 { "powerpc64", PER_LINUX },
3176 { "s390x", PER_LINUX },
3177 { "x86_64", PER_LINUX },
3178 };
3179 size_t len = sizeof(pername) / sizeof(pername[0]);
3180
3181 for (i = 0; i < len; i++)
3182 if (!strcmp(pername[i].name, arch))
3183 return pername[i].per;
3184 #endif
3185
3186 return -1;
3187 }
3188
3189 int lxc_fill_elevated_privileges(char *flaglist, int *flags)
3190 {
3191 char *token;
3192 int i, aflag;
3193 struct {
3194 const char *token;
3195 int flag;
3196 } all_privs[] = {
3197 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
3198 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
3199 { "LSM", LXC_ATTACH_LSM_EXEC },
3200 { NULL, 0 }
3201 };
3202
3203 if (!flaglist) {
3204 /* For the sake of backward compatibility, drop all privileges
3205 * if none is specified.
3206 */
3207 for (i = 0; all_privs[i].token; i++)
3208 *flags |= all_privs[i].flag;
3209
3210 return 0;
3211 }
3212
3213 lxc_iterate_parts(token, flaglist, "|") {
3214 aflag = -1;
3215
3216 for (i = 0; all_privs[i].token; i++)
3217 if (!strcmp(all_privs[i].token, token))
3218 aflag = all_privs[i].flag;
3219
3220 if (aflag < 0)
3221 return -1;
3222
3223 *flags |= aflag;
3224 }
3225
3226 return 0;
3227 }
3228
3229 /* Write out a configuration file. */
3230 int write_config(int fd, const struct lxc_conf *conf)
3231 {
3232 int ret;
3233 size_t len = conf->unexpanded_len;
3234
3235 if (len == 0)
3236 return 0;
3237
3238 ret = lxc_write_nointr(fd, conf->unexpanded_config, len);
3239 if (ret < 0) {
3240 SYSERROR("Failed to write configuration file");
3241 return -1;
3242 }
3243
3244 return 0;
3245 }
3246
3247 bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
3248 const char *v)
3249 {
3250 __do_free char *tmp = NULL;
3251 int ret;
3252 size_t len;
3253
3254 len = strlen(key) + strlen(v) + 4;
3255 tmp = must_realloc(NULL, len);
3256
3257 if (lxc_config_value_empty(v))
3258 ret = snprintf(tmp, len, "%s =", key);
3259 else
3260 ret = snprintf(tmp, len, "%s = %s", key, v);
3261 if (ret < 0 || ret >= len)
3262 return false;
3263
3264 /* Save the line verbatim into unexpanded_conf */
3265 if (append_unexp_config_line(tmp, conf))
3266 return false;
3267
3268 return true;
3269 }
3270
3271 void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
3272 bool rm_subkeys)
3273 {
3274 char *lend;
3275 char *lstart = conf->unexpanded_config;
3276
3277 if (!conf->unexpanded_config)
3278 return;
3279
3280 while (*lstart) {
3281 lend = strchr(lstart, '\n');
3282 char v;
3283
3284 if (!lend)
3285 lend = lstart + strlen(lstart);
3286 else
3287 lend++;
3288
3289 if (strncmp(lstart, key, strlen(key)) != 0) {
3290 lstart = lend;
3291 continue;
3292 }
3293
3294 if (!rm_subkeys) {
3295 v = lstart[strlen(key)];
3296 if (!isspace(v) && v != '=') {
3297 lstart = lend;
3298 continue;
3299 }
3300 }
3301
3302 conf->unexpanded_len -= (lend - lstart);
3303
3304 if (*lend == '\0') {
3305 *lstart = '\0';
3306 return;
3307 }
3308
3309 memmove(lstart, lend, strlen(lend) + 1);
3310 }
3311 }
3312
3313 bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
3314 const char *newpath, const char *oldname,
3315 const char *newname, const char *ovldir)
3316 {
3317 __do_free char *newdir = NULL,
3318 *olddir = NULL;
3319 int ret;
3320 char *lend, *p, *q;
3321 size_t newdirlen, olddirlen;
3322 char *lstart = conf->unexpanded_config;
3323 const char *key = "lxc.mount.entry";
3324
3325 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
3326 olddir = must_realloc(NULL, olddirlen + 1);
3327 ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
3328 oldname);
3329 if (ret < 0 || ret >= olddirlen + 1)
3330 return false;
3331
3332 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
3333 newdir = must_realloc(NULL, newdirlen + 1);
3334 ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
3335 newname);
3336 if (ret < 0 || ret >= newdirlen + 1)
3337 return false;
3338
3339 if (!conf->unexpanded_config)
3340 return true;
3341
3342 while (*lstart) {
3343 lend = strchr(lstart, '\n');
3344 if (!lend)
3345 lend = lstart + strlen(lstart);
3346 else
3347 lend++;
3348
3349 if (strncmp(lstart, key, strlen(key)) != 0)
3350 goto next;
3351
3352 p = strchr(lstart + strlen(key), '=');
3353 if (!p)
3354 goto next;
3355 p++;
3356
3357 while (isblank(*p))
3358 p++;
3359
3360 if (p >= lend)
3361 goto next;
3362
3363 /* Whenever a lxc.mount.entry entry is found in a line we check
3364 * if the substring "overlay" is present before doing any
3365 * further work. We check for "overlay" because substrings need
3366 * to have at least one space before them in a valid overlay
3367 * lxc.mount.entry (/A B overlay). When the space before is
3368 * missing it is very likely that these substrings are part of a
3369 * path or something else. (Checking q >= lend ensures that we
3370 * only count matches in the current line.) */
3371 q = strstr(p, " overlay");
3372 if (!q || q >= lend)
3373 goto next;
3374
3375 if (!(q = strstr(p, olddir)) || (q >= lend))
3376 goto next;
3377
3378 /* replace the olddir with newdir */
3379 if (olddirlen >= newdirlen) {
3380 size_t diff = olddirlen - newdirlen;
3381 memcpy(q, newdir, newdirlen);
3382
3383 if (olddirlen != newdirlen) {
3384 memmove(q + newdirlen, q + newdirlen + diff,
3385 strlen(q) - newdirlen - diff + 1);
3386 lend -= diff;
3387 conf->unexpanded_len -= diff;
3388 }
3389 } else {
3390 char *new;
3391 size_t diff = newdirlen - olddirlen;
3392 size_t oldlen = conf->unexpanded_len;
3393 size_t newlen = oldlen + diff;
3394 size_t poffset = q - conf->unexpanded_config;
3395
3396 new = realloc(conf->unexpanded_config, newlen + 1);
3397 if (!new)
3398 return false;
3399
3400 conf->unexpanded_len = newlen;
3401 conf->unexpanded_alloced = newlen + 1;
3402 new[newlen - 1] = '\0';
3403 lend = new + (lend - conf->unexpanded_config);
3404
3405 /* Move over the remainder to make room for the newdir.
3406 */
3407 memmove(new + poffset + newdirlen,
3408 new + poffset + olddirlen,
3409 oldlen - poffset - olddirlen + 1);
3410 conf->unexpanded_config = new;
3411
3412 memcpy(new + poffset, newdir, newdirlen);
3413 lend += diff;
3414 }
3415
3416 next:
3417 lstart = lend;
3418 }
3419
3420 return true;
3421 }
3422
3423 bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
3424 const char *newpath, const char *oldname,
3425 const char *newname)
3426 {
3427 __do_free char *newdir = NULL,
3428 *olddir = NULL;
3429 int ret;
3430 char *lend, *p;
3431 char *lstart = conf->unexpanded_config;
3432 size_t newdirlen, olddirlen;
3433 const char *key = "lxc.hook";
3434
3435 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
3436 olddir = must_realloc(NULL, olddirlen + 1);
3437 ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
3438 if (ret < 0 || ret >= olddirlen + 1)
3439 return false;
3440
3441 newdirlen = strlen(newpath) + strlen(newname) + 1;
3442 newdir = must_realloc(NULL, newdirlen + 1);
3443 ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
3444 if (ret < 0 || ret >= newdirlen + 1)
3445 return false;
3446
3447 if (!conf->unexpanded_config)
3448 return true;
3449
3450 while (*lstart) {
3451 lend = strchr(lstart, '\n');
3452 if (!lend)
3453 lend = lstart + strlen(lstart);
3454 else
3455 lend++;
3456
3457 if (strncmp(lstart, key, strlen(key)) != 0)
3458 goto next;
3459
3460 p = strchr(lstart + strlen(key), '=');
3461 if (!p)
3462 goto next;
3463 p++;
3464
3465 while (isblank(*p))
3466 p++;
3467
3468 if (p >= lend)
3469 goto next;
3470
3471 if (strncmp(p, olddir, strlen(olddir)) != 0)
3472 goto next;
3473
3474 /* replace the olddir with newdir */
3475 if (olddirlen >= newdirlen) {
3476 size_t diff = olddirlen - newdirlen;
3477 memcpy(p, newdir, newdirlen);
3478
3479 if (olddirlen != newdirlen) {
3480 memmove(p + newdirlen, p + newdirlen + diff,
3481 strlen(p) - newdirlen - diff + 1);
3482 lend -= diff;
3483 conf->unexpanded_len -= diff;
3484 }
3485 } else {
3486 char *new;
3487 size_t diff = newdirlen - olddirlen;
3488 size_t oldlen = conf->unexpanded_len;
3489 size_t newlen = oldlen + diff;
3490 size_t poffset = p - conf->unexpanded_config;
3491
3492 new = realloc(conf->unexpanded_config, newlen + 1);
3493 if (!new)
3494 return false;
3495
3496 conf->unexpanded_len = newlen;
3497 conf->unexpanded_alloced = newlen + 1;
3498 new[newlen - 1] = '\0';
3499 lend = new + (lend - conf->unexpanded_config);
3500
3501 /* Move over the remainder to make room for the newdir.
3502 */
3503 memmove(new + poffset + newdirlen,
3504 new + poffset + olddirlen,
3505 oldlen - poffset - olddirlen + 1);
3506 conf->unexpanded_config = new;
3507
3508 memcpy(new + poffset, newdir, newdirlen);
3509 lend += diff;
3510 }
3511
3512 next:
3513 lstart = lend;
3514 }
3515
3516 return true;
3517 }
3518
3519 #define DO(cmd) \
3520 { \
3521 if (!(cmd)) { \
3522 ERROR("Error writing to new config"); \
3523 return false; \
3524 } \
3525 }
3526
3527 /* This is called only from clone. We wish to update all hwaddrs in the
3528 * unexpanded config file. We can't/don't want to update any which come from
3529 * lxc.includes (there shouldn't be any).
3530 * We can't just walk the c->lxc-conf->network list because that includes netifs
3531 * from the include files. So we update the ones which we find in the unexp
3532 * config file, then find the original macaddr in the conf->network, and update
3533 * that to the same value.
3534 */
3535 bool network_new_hwaddrs(struct lxc_conf *conf)
3536 {
3537 char *lend, *p, *p2;
3538 struct lxc_list *it;
3539 char *lstart = conf->unexpanded_config;
3540
3541 if (!conf->unexpanded_config)
3542 return true;
3543
3544 while (*lstart) {
3545 char newhwaddr[18], oldhwaddr[17];
3546
3547 lend = strchr(lstart, '\n');
3548 if (!lend)
3549 lend = lstart + strlen(lstart);
3550 else
3551 lend++;
3552
3553 if (!lxc_config_net_is_hwaddr(lstart)) {
3554 lstart = lend;
3555 continue;
3556 }
3557
3558 p = strchr(lstart, '=');
3559 if (!p) {
3560 lstart = lend;
3561 continue;
3562 }
3563
3564 p++;
3565 while (isblank(*p))
3566 p++;
3567 if (!*p)
3568 return true;
3569
3570 p2 = p;
3571 while (*p2 && !isblank(*p2) && *p2 != '\n')
3572 p2++;
3573
3574 if ((p2 - p) != 17) {
3575 WARN("Bad hwaddr entry");
3576 lstart = lend;
3577 continue;
3578 }
3579
3580 memcpy(oldhwaddr, p, 17);
3581
3582 if (!new_hwaddr(newhwaddr))
3583 return false;
3584
3585 memcpy(p, newhwaddr, 17);
3586 lxc_list_for_each(it, &conf->network) {
3587 struct lxc_netdev *n = it->elem;
3588
3589 if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
3590 memcpy(n->hwaddr, newhwaddr, 17);
3591 }
3592
3593 lstart = lend;
3594 }
3595
3596 return true;
3597 }
3598
3599 static int set_config_ephemeral(const char *key, const char *value,
3600 struct lxc_conf *lxc_conf, void *data)
3601 {
3602 if (lxc_config_value_empty(value)) {
3603 lxc_conf->ephemeral = 0;
3604 return 0;
3605 }
3606
3607 if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
3608 return -1;
3609
3610 if (lxc_conf->ephemeral > 1)
3611 return -1;
3612
3613 return 0;
3614 }
3615
3616 static int set_config_log_syslog(const char *key, const char *value,
3617 struct lxc_conf *lxc_conf, void *data)
3618 {
3619 int facility;
3620
3621 if (lxc_conf->syslog) {
3622 free(lxc_conf->syslog);
3623 lxc_conf->syslog = NULL;
3624 }
3625
3626 if (lxc_config_value_empty(value))
3627 return 0;
3628
3629 facility = lxc_syslog_priority_to_int(value);
3630 if (facility == -EINVAL)
3631 return -1;
3632
3633 lxc_log_syslog(facility);
3634
3635 return set_config_string_item(&lxc_conf->syslog, value);
3636 }
3637
3638 static int set_config_no_new_privs(const char *key, const char *value,
3639 struct lxc_conf *lxc_conf, void *data)
3640 {
3641 unsigned int v;
3642
3643 if (lxc_config_value_empty(value)) {
3644 lxc_conf->no_new_privs = false;
3645 return 0;
3646 }
3647
3648 if (lxc_safe_uint(value, &v) < 0)
3649 return -1;
3650
3651 if (v > 1)
3652 return -1;
3653
3654 lxc_conf->no_new_privs = v ? true : false;
3655
3656 return 0;
3657 }
3658
3659 /* Callbacks to get configuration items. */
3660 static int get_config_personality(const char *key, char *retv, int inlen,
3661 struct lxc_conf *c, void *data)
3662 {
3663 int fulllen = 0;
3664
3665 if (!retv)
3666 inlen = 0;
3667 else
3668 memset(retv, 0, inlen);
3669
3670 #if HAVE_SYS_PERSONALITY_H
3671 int len = 0;
3672
3673 switch (c->personality) {
3674 case PER_LINUX32:
3675 strprint(retv, inlen, "i686");
3676 break;
3677 case PER_LINUX:
3678 strprint(retv, inlen, "x86_64");
3679 break;
3680 default:
3681 break;
3682 }
3683 #endif
3684
3685 return fulllen;
3686 }
3687
3688 static int get_config_pty_max(const char *key, char *retv, int inlen,
3689 struct lxc_conf *c, void *data)
3690 {
3691 return lxc_get_conf_size_t(c, retv, inlen, c->pty_max);
3692 }
3693
3694 static int get_config_tty_max(const char *key, char *retv, int inlen,
3695 struct lxc_conf *c, void *data)
3696 {
3697 return lxc_get_conf_size_t(c, retv, inlen, c->ttys.max);
3698 }
3699
3700 static int get_config_tty_dir(const char *key, char *retv, int inlen,
3701 struct lxc_conf *c, void *data)
3702 {
3703 return lxc_get_conf_str(retv, inlen, c->ttys.dir);
3704 }
3705
3706 static int get_config_apparmor_profile(const char *key, char *retv, int inlen,
3707 struct lxc_conf *c, void *data)
3708 {
3709 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
3710 }
3711
3712 static int get_config_apparmor_allow_incomplete(const char *key, char *retv,
3713 int inlen, struct lxc_conf *c,
3714 void *data)
3715 {
3716 return lxc_get_conf_int(c, retv, inlen,
3717 c->lsm_aa_allow_incomplete);
3718 }
3719
3720 static int get_config_apparmor_allow_nesting(const char *key, char *retv,
3721 int inlen, struct lxc_conf *c,
3722 void *data)
3723 {
3724 return lxc_get_conf_int(c, retv, inlen,
3725 c->lsm_aa_allow_nesting);
3726 }
3727
3728 static int get_config_apparmor_raw(const char *key, char *retv,
3729 int inlen, struct lxc_conf *c,
3730 void *data)
3731 {
3732 int len;
3733 struct lxc_list *it;
3734 int fulllen = 0;
3735
3736 if (!retv)
3737 inlen = 0;
3738 else
3739 memset(retv, 0, inlen);
3740
3741 lxc_list_for_each(it, &c->lsm_aa_raw) {
3742 strprint(retv, inlen, "%s\n", (char *)it->elem);
3743 }
3744
3745 return fulllen;
3746 }
3747
3748 static int get_config_selinux_context(const char *key, char *retv, int inlen,
3749 struct lxc_conf *c, void *data)
3750 {
3751 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
3752 }
3753
3754 static int get_config_selinux_context_keyring(const char *key, char *retv, int inlen,
3755 struct lxc_conf *c, void *data)
3756 {
3757 return lxc_get_conf_str(retv, inlen, c->lsm_se_keyring_context);
3758 }
3759
3760 static int get_config_keyring_session(const char *key, char *retv, int inlen,
3761 struct lxc_conf *c, void *data)
3762 {
3763 return lxc_get_conf_bool(c, retv, inlen, c->keyring_disable_session);
3764 }
3765
3766
3767 /* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
3768 * just the value(s) will be printed. Since there still could be more than one,
3769 * it is newline-separated.
3770 * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
3771 * have newlines?)
3772 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
3773 * 'lxc.cgroup.subsystem.key = value' format.
3774 */
3775 static int __get_config_cgroup_controller(const char *key, char *retv,
3776 int inlen, struct lxc_conf *c,
3777 int version)
3778 {
3779 int len;
3780 size_t namespaced_token_len;
3781 char *global_token, *namespaced_token;
3782 struct lxc_list *it;
3783 int fulllen = 0;
3784 bool get_all = false;
3785
3786 if (!retv)
3787 inlen = 0;
3788 else
3789 memset(retv, 0, inlen);
3790
3791 if (version == CGROUP2_SUPER_MAGIC) {
3792 global_token = "lxc.cgroup2";
3793 namespaced_token = "lxc.cgroup2.";
3794 namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
3795 } else if (version == CGROUP_SUPER_MAGIC) {
3796 global_token = "lxc.cgroup";
3797 namespaced_token = "lxc.cgroup.";
3798 namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
3799 } else {
3800 return -1;
3801 }
3802
3803 if (strcmp(key, global_token) == 0)
3804 get_all = true;
3805 else if (strncmp(key, namespaced_token, namespaced_token_len) == 0)
3806 key += namespaced_token_len;
3807 else
3808 return -1;
3809
3810 lxc_list_for_each(it, &c->cgroup) {
3811 struct lxc_cgroup *cg = it->elem;
3812
3813 if (get_all) {
3814 if (version != cg->version)
3815 continue;
3816
3817 strprint(retv, inlen, "%s.%s = %s\n", global_token,
3818 cg->subsystem, cg->value);
3819 } else if (strcmp(cg->subsystem, key) == 0) {
3820 strprint(retv, inlen, "%s\n", cg->value);
3821 }
3822 }
3823
3824 return fulllen;
3825 }
3826
3827 static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
3828 struct lxc_conf *c, void *data)
3829 {
3830 return __get_config_cgroup_controller(key, retv, inlen, c,
3831 CGROUP_SUPER_MAGIC);
3832 }
3833
3834 static int get_config_cgroup2_controller(const char *key, char *retv, int inlen,
3835 struct lxc_conf *c, void *data)
3836 {
3837 return __get_config_cgroup_controller(key, retv, inlen, c,
3838 CGROUP2_SUPER_MAGIC);
3839 }
3840
3841 static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
3842 struct lxc_conf *lxc_conf, void *data)
3843 {
3844 int len;
3845 int fulllen = 0;
3846
3847 if (!retv)
3848 inlen = 0;
3849 else
3850 memset(retv, 0, inlen);
3851
3852 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.dir);
3853
3854 return fulllen;
3855 }
3856
3857 static int get_config_cgroup_monitor_dir(const char *key, char *retv, int inlen,
3858 struct lxc_conf *lxc_conf, void *data)
3859 {
3860 int len;
3861 int fulllen = 0;
3862
3863 if (!retv)
3864 inlen = 0;
3865 else
3866 memset(retv, 0, inlen);
3867
3868 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.monitor_dir);
3869
3870 return fulllen;
3871 }
3872
3873 static int get_config_cgroup_container_dir(const char *key, char *retv,
3874 int inlen,
3875 struct lxc_conf *lxc_conf,
3876 void *data)
3877 {
3878 int len;
3879 int fulllen = 0;
3880
3881 if (!retv)
3882 inlen = 0;
3883 else
3884 memset(retv, 0, inlen);
3885
3886 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.container_dir);
3887
3888 return fulllen;
3889 }
3890
3891 static int get_config_cgroup_container_inner_dir(const char *key, char *retv,
3892 int inlen,
3893 struct lxc_conf *lxc_conf,
3894 void *data)
3895 {
3896 int len;
3897 int fulllen = 0;
3898
3899 if (!retv)
3900 inlen = 0;
3901 else
3902 memset(retv, 0, inlen);
3903
3904 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.namespace_dir);
3905
3906 return fulllen;
3907 }
3908
3909 static inline int get_config_cgroup_relative(const char *key, char *retv,
3910 int inlen, struct lxc_conf *lxc_conf,
3911 void *data)
3912 {
3913 return lxc_get_conf_int(lxc_conf, retv, inlen,
3914 lxc_conf->cgroup_meta.relative);
3915 }
3916
3917 static int get_config_idmaps(const char *key, char *retv, int inlen,
3918 struct lxc_conf *c, void *data)
3919 {
3920 struct lxc_list *it;
3921 int len, listlen, ret;
3922 int fulllen = 0;
3923 /* "u 1000 1000000 65536"
3924 *
3925 * let's render this as
3926 *
3927 * sizeof(char)
3928 * +
3929 * sizeof(" ")
3930 * +
3931 * sizeof(uint32_t)
3932 * +
3933 * sizeof(" ")
3934 * +
3935 * sizeof(uint32_t)
3936 * +
3937 * sizeof(" ")
3938 * +
3939 * sizeof(uint32_t)
3940 * +
3941 * \0
3942 */
3943 #define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
3944 char buf[__LXC_IDMAP_STR_BUF];
3945
3946 if (!retv)
3947 inlen = 0;
3948 else
3949 memset(retv, 0, inlen);
3950
3951 listlen = lxc_list_len(&c->id_map);
3952 lxc_list_for_each(it, &c->id_map) {
3953 struct id_map *map = it->elem;
3954 ret = snprintf(buf, __LXC_IDMAP_STR_BUF, "%c %lu %lu %lu",
3955 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
3956 map->nsid, map->hostid, map->range);
3957 if (ret < 0 || ret >= __LXC_IDMAP_STR_BUF)
3958 return -1;
3959
3960 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
3961 }
3962
3963 return fulllen;
3964 }
3965
3966 static int get_config_log_level(const char *key, char *retv, int inlen,
3967 struct lxc_conf *c, void *data)
3968 {
3969 const char *v;
3970 v = lxc_log_priority_to_string(c->loglevel);
3971 return lxc_get_conf_str(retv, inlen, v);
3972 }
3973
3974 static int get_config_log_file(const char *key, char *retv, int inlen,
3975 struct lxc_conf *c, void *data)
3976 {
3977 return lxc_get_conf_str(retv, inlen, c->logfile);
3978 }
3979
3980 static int get_config_mount_fstab(const char *key, char *retv, int inlen,
3981 struct lxc_conf *c, void *data)
3982 {
3983 return lxc_get_conf_str(retv, inlen, c->fstab);
3984 }
3985
3986 static int get_config_mount_auto(const char *key, char *retv, int inlen,
3987 struct lxc_conf *c, void *data)
3988 {
3989 int len, fulllen = 0;
3990 const char *sep = "";
3991
3992 if (!retv)
3993 inlen = 0;
3994 else
3995 memset(retv, 0, inlen);
3996
3997 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
3998 return 0;
3999
4000 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
4001 case LXC_AUTO_PROC_MIXED:
4002 strprint(retv, inlen, "%sproc:mixed", sep);
4003 sep = " ";
4004 break;
4005 case LXC_AUTO_PROC_RW:
4006 strprint(retv, inlen, "%sproc:rw", sep);
4007 sep = " ";
4008 break;
4009 default:
4010 break;
4011 }
4012
4013 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
4014 case LXC_AUTO_SYS_RO:
4015 strprint(retv, inlen, "%ssys:ro", sep);
4016 sep = " ";
4017 break;
4018 case LXC_AUTO_SYS_RW:
4019 strprint(retv, inlen, "%ssys:rw", sep);
4020 sep = " ";
4021 break;
4022 case LXC_AUTO_SYS_MIXED:
4023 strprint(retv, inlen, "%ssys:mixed", sep);
4024 sep = " ";
4025 break;
4026 default:
4027 break;
4028 }
4029
4030 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
4031 case LXC_AUTO_CGROUP_NOSPEC:
4032 strprint(retv, inlen, "%scgroup", sep);
4033 break;
4034 case LXC_AUTO_CGROUP_MIXED:
4035 strprint(retv, inlen, "%scgroup:mixed", sep);
4036 break;
4037 case LXC_AUTO_CGROUP_RO:
4038 strprint(retv, inlen, "%scgroup:ro", sep);
4039 break;
4040 case LXC_AUTO_CGROUP_RW:
4041 strprint(retv, inlen, "%scgroup:rw", sep);
4042 break;
4043 case LXC_AUTO_CGROUP_FULL_NOSPEC:
4044 strprint(retv, inlen, "%scgroup-full", sep);
4045 break;
4046 case LXC_AUTO_CGROUP_FULL_MIXED:
4047 strprint(retv, inlen, "%scgroup-full:mixed", sep);
4048 break;
4049 case LXC_AUTO_CGROUP_FULL_RO:
4050 strprint(retv, inlen, "%scgroup-full:ro", sep);
4051 break;
4052 case LXC_AUTO_CGROUP_FULL_RW:
4053 strprint(retv, inlen, "%scgroup-full:rw", sep);
4054 break;
4055 default:
4056 break;
4057 }
4058
4059 return fulllen;
4060 }
4061
4062 static int get_config_mount(const char *key, char *retv, int inlen,
4063 struct lxc_conf *c, void *data)
4064 {
4065 int len, fulllen = 0;
4066 struct lxc_list *it;
4067
4068 if (!retv)
4069 inlen = 0;
4070 else
4071 memset(retv, 0, inlen);
4072
4073 lxc_list_for_each(it, &c->mount_list) {
4074 strprint(retv, inlen, "%s\n", (char *)it->elem);
4075 }
4076
4077 return fulllen;
4078 }
4079
4080 static int get_config_rootfs_path(const char *key, char *retv, int inlen,
4081 struct lxc_conf *c, void *data)
4082 {
4083 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
4084 }
4085
4086 static int get_config_rootfs_managed(const char *key, char *retv, int inlen,
4087 struct lxc_conf *c, void *data)
4088 {
4089 return lxc_get_conf_bool(c, retv, inlen, c->rootfs.managed);
4090 }
4091
4092 static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
4093 struct lxc_conf *c, void *data)
4094 {
4095 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
4096 }
4097
4098 static int get_config_rootfs_options(const char *key, char *retv, int inlen,
4099 struct lxc_conf *c, void *data)
4100 {
4101 return lxc_get_conf_str(retv, inlen, c->rootfs.options);
4102 }
4103
4104 static int get_config_uts_name(const char *key, char *retv, int inlen,
4105 struct lxc_conf *c, void *data)
4106 {
4107 return lxc_get_conf_str(
4108 retv, inlen,
4109 c->utsname ? c->utsname->nodename : NULL);
4110 }
4111
4112 static int get_config_hooks(const char *key, char *retv, int inlen,
4113 struct lxc_conf *c, void *data)
4114 {
4115 char *subkey;
4116 int len, fulllen = 0, found = -1;
4117 struct lxc_list *it;
4118 int i;
4119
4120 subkey = strchr(key, '.');
4121 if (!subkey)
4122 return -1;
4123
4124 subkey = strchr(subkey + 1, '.');
4125 if (!subkey)
4126 return -1;
4127 subkey++;
4128 if (*subkey == '\0')
4129 return -1;
4130
4131 for (i = 0; i < NUM_LXC_HOOKS; i++) {
4132 if (strcmp(lxchook_names[i], subkey) == 0) {
4133 found = i;
4134 break;
4135 }
4136 }
4137
4138 if (found == -1)
4139 return -1;
4140
4141 if (!retv)
4142 inlen = 0;
4143 else
4144 memset(retv, 0, inlen);
4145
4146 lxc_list_for_each(it, &c->hooks[found]) {
4147 strprint(retv, inlen, "%s\n", (char *)it->elem);
4148 }
4149
4150 return fulllen;
4151 }
4152
4153 static int get_config_hooks_version(const char *key, char *retv, int inlen,
4154 struct lxc_conf *c, void *data)
4155 {
4156 return lxc_get_conf_int(c, retv, inlen, c->hooks_version);
4157 }
4158
4159 static int get_config_net(const char *key, char *retv, int inlen,
4160 struct lxc_conf *c, void *data)
4161 {
4162 int len, fulllen = 0;
4163 struct lxc_list *it;
4164
4165 if (!retv)
4166 inlen = 0;
4167 else
4168 memset(retv, 0, inlen);
4169
4170 lxc_list_for_each(it, &c->network) {
4171 struct lxc_netdev *n = it->elem;
4172 const char *t = lxc_net_type_to_str(n->type);
4173 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
4174 }
4175
4176 return fulllen;
4177 }
4178
4179 static int get_config_cap_drop(const char *key, char *retv, int inlen,
4180 struct lxc_conf *c, void *data)
4181 {
4182 int len, fulllen = 0;
4183 struct lxc_list *it;
4184
4185 if (!retv)
4186 inlen = 0;
4187 else
4188 memset(retv, 0, inlen);
4189
4190 lxc_list_for_each(it, &c->caps) {
4191 strprint(retv, inlen, "%s\n", (char *)it->elem);
4192 }
4193
4194 return fulllen;
4195 }
4196
4197 static int get_config_cap_keep(const char *key, char *retv, int inlen,
4198 struct lxc_conf *c, void *data)
4199 {
4200 int len, fulllen = 0;
4201 struct lxc_list *it;
4202
4203 if (!retv)
4204 inlen = 0;
4205 else
4206 memset(retv, 0, inlen);
4207
4208 lxc_list_for_each(it, &c->keepcaps) {
4209 strprint(retv, inlen, "%s\n", (char *)it->elem);
4210 }
4211
4212 return fulllen;
4213 }
4214
4215 static int get_config_console_path(const char *key, char *retv, int inlen,
4216 struct lxc_conf *c, void *data)
4217 {
4218 return lxc_get_conf_str(retv, inlen, c->console.path);
4219 }
4220
4221 static int get_config_console_logfile(const char *key, char *retv, int inlen,
4222 struct lxc_conf *c, void *data)
4223 {
4224 return lxc_get_conf_str(retv, inlen, c->console.log_path);
4225 }
4226
4227 static int get_config_console_rotate(const char *key, char *retv, int inlen,
4228 struct lxc_conf *c, void *data)
4229 {
4230 return lxc_get_conf_int(c, retv, inlen, c->console.log_rotate);
4231 }
4232
4233
4234 static int get_config_console_buffer_size(const char *key, char *retv,
4235 int inlen, struct lxc_conf *c,
4236 void *data)
4237 {
4238 return lxc_get_conf_uint64(c, retv, inlen, c->console.buffer_size);
4239 }
4240
4241 static int get_config_console_size(const char *key, char *retv, int inlen,
4242 struct lxc_conf *c, void *data)
4243 {
4244 return lxc_get_conf_uint64(c, retv, inlen, c->console.log_size);
4245 }
4246
4247 static int get_config_seccomp_allow_nesting(const char *key, char *retv,
4248 int inlen, struct lxc_conf *c,
4249 void *data)
4250 {
4251 #ifdef HAVE_SECCOMP
4252 return lxc_get_conf_int(c, retv, inlen, c->seccomp.allow_nesting);
4253 #else
4254 errno = ENOSYS;
4255 return -1;
4256 #endif
4257 }
4258
4259 static int get_config_seccomp_notify_cookie(const char *key, char *retv, int inlen,
4260 struct lxc_conf *c, void *data)
4261 {
4262 #ifdef HAVE_SECCOMP_NOTIFY
4263 return lxc_get_conf_str(retv, inlen, c->seccomp.notifier.cookie);
4264 #else
4265 return ret_set_errno(-1, ENOSYS);
4266 #endif
4267 }
4268
4269 static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inlen,
4270 struct lxc_conf *c, void *data)
4271 {
4272 #ifdef HAVE_SECCOMP_NOTIFY
4273 return lxc_get_conf_str(retv, inlen,
4274 (c->seccomp.notifier.proxy_addr.sun_path[0]) == '/'
4275 ? &c->seccomp.notifier.proxy_addr.sun_path[0]
4276 : &c->seccomp.notifier.proxy_addr.sun_path[1]);
4277 #else
4278 return ret_set_errno(-1, ENOSYS);
4279 #endif
4280 }
4281
4282 static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
4283 struct lxc_conf *c, void *data)
4284 {
4285 return lxc_get_conf_str(retv, inlen, c->seccomp.seccomp);
4286 }
4287
4288 static int get_config_autodev(const char *key, char *retv, int inlen,
4289 struct lxc_conf *c, void *data)
4290 {
4291 return lxc_get_conf_int(c, retv, inlen, c->autodev);
4292 }
4293
4294 static int get_config_autodev_tmpfs_size(const char *key, char *retv, int inlen,
4295 struct lxc_conf *c, void *data)
4296 {
4297 return lxc_get_conf_int(c, retv, inlen, c->autodevtmpfssize);
4298 }
4299
4300 static int get_config_signal_halt(const char *key, char *retv, int inlen,
4301 struct lxc_conf *c, void *data)
4302 {
4303 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
4304 }
4305
4306 static int get_config_signal_reboot(const char *key, char *retv, int inlen,
4307 struct lxc_conf *c, void *data)
4308 {
4309 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
4310 }
4311
4312 static int get_config_signal_stop(const char *key, char *retv, int inlen,
4313 struct lxc_conf *c, void *data)
4314 {
4315 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
4316 }
4317
4318 static int get_config_start(const char *key, char *retv, int inlen,
4319 struct lxc_conf *c, void *data)
4320 {
4321 if (strcmp(key + 10, "auto") == 0)
4322 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
4323 else if (strcmp(key + 10, "delay") == 0)
4324 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
4325 else if (strcmp(key + 10, "order") == 0)
4326 return lxc_get_conf_int(c, retv, inlen, c->start_order);
4327
4328 return -1;
4329 }
4330
4331 static int get_config_log_syslog(const char *key, char *retv, int inlen,
4332 struct lxc_conf *c, void *data)
4333 {
4334 return lxc_get_conf_str(retv, inlen, c->syslog);
4335 }
4336
4337 static int get_config_monitor(const char *key, char *retv, int inlen,
4338 struct lxc_conf *c, void *data)
4339 {
4340 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
4341 }
4342
4343 static int get_config_monitor_signal_pdeath(const char *key, char *retv,
4344 int inlen, struct lxc_conf *c,
4345 void *data)
4346 {
4347 return lxc_get_conf_int(c, retv, inlen, c->monitor_signal_pdeath);
4348 }
4349
4350 static int get_config_group(const char *key, char *retv, int inlen,
4351 struct lxc_conf *c, void *data)
4352 {
4353 int len, fulllen = 0;
4354 struct lxc_list *it;
4355
4356 if (!retv)
4357 inlen = 0;
4358 else
4359 memset(retv, 0, inlen);
4360
4361 lxc_list_for_each(it, &c->groups) {
4362 strprint(retv, inlen, "%s\n", (char *)it->elem);
4363 }
4364
4365 return fulllen;
4366 }
4367
4368 static int get_config_environment(const char *key, char *retv, int inlen,
4369 struct lxc_conf *c, void *data)
4370 {
4371 int len, fulllen = 0;
4372 struct lxc_list *it;
4373
4374 if (!retv)
4375 inlen = 0;
4376 else
4377 memset(retv, 0, inlen);
4378
4379 lxc_list_for_each(it, &c->environment) {
4380 strprint(retv, inlen, "%s\n", (char *)it->elem);
4381 }
4382
4383 return fulllen;
4384 }
4385
4386 static int get_config_execute_cmd(const char *key, char *retv, int inlen,
4387 struct lxc_conf *c, void *data)
4388 {
4389 return lxc_get_conf_str(retv, inlen, c->execute_cmd);
4390 }
4391
4392 static int get_config_init_cmd(const char *key, char *retv, int inlen,
4393 struct lxc_conf *c, void *data)
4394 {
4395 return lxc_get_conf_str(retv, inlen, c->init_cmd);
4396 }
4397
4398 static int get_config_init_cwd(const char *key, char *retv, int inlen,
4399 struct lxc_conf *c, void *data)
4400 {
4401 return lxc_get_conf_str(retv, inlen, c->init_cwd);
4402 }
4403
4404 static int get_config_init_uid(const char *key, char *retv, int inlen,
4405 struct lxc_conf *c, void *data)
4406 {
4407 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
4408 }
4409
4410 static int get_config_init_gid(const char *key, char *retv, int inlen,
4411 struct lxc_conf *c, void *data)
4412 {
4413 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
4414 }
4415
4416 static int get_config_ephemeral(const char *key, char *retv, int inlen,
4417 struct lxc_conf *c, void *data)
4418 {
4419 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
4420 }
4421
4422 static int get_config_no_new_privs(const char *key, char *retv, int inlen,
4423 struct lxc_conf *c, void *data)
4424 {
4425 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
4426 }
4427
4428 /* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
4429 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
4430 * printed, in 'lxc.prlimit.resource = value' format.
4431 */
4432 static int get_config_prlimit(const char *key, char *retv, int inlen,
4433 struct lxc_conf *c, void *data)
4434 {
4435 int fulllen = 0, len;
4436 bool get_all = false;
4437 struct lxc_list *it;
4438
4439 if (!retv)
4440 inlen = 0;
4441 else
4442 memset(retv, 0, inlen);
4443
4444 if (!strcmp(key, "lxc.prlimit"))
4445 get_all = true;
4446 else if (strncmp(key, "lxc.prlimit.", 12) == 0)
4447 key += 12;
4448 else
4449 return -1;
4450
4451 lxc_list_for_each(it, &c->limits) {
4452 /* 2 colon separated 64 bit integers or the word 'unlimited' */
4453 char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
4454 int partlen;
4455 struct lxc_limit *lim = it->elem;
4456
4457 if (lim->limit.rlim_cur == RLIM_INFINITY) {
4458 memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1);
4459 partlen = STRLITERALLEN("unlimited");
4460 } else {
4461 partlen = sprintf(buf, "%" PRIu64,
4462 (uint64_t)lim->limit.rlim_cur);
4463 }
4464
4465 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
4466 if (lim->limit.rlim_max == RLIM_INFINITY)
4467 memcpy(buf + partlen, ":unlimited",
4468 STRLITERALLEN(":unlimited") + 1);
4469 else
4470 sprintf(buf + partlen, ":%" PRIu64,
4471 (uint64_t)lim->limit.rlim_max);
4472 }
4473
4474 if (get_all) {
4475 strprint(retv, inlen, "lxc.prlimit.%s = %s\n",
4476 lim->resource, buf);
4477 } else if (strcmp(lim->resource, key) == 0) {
4478 strprint(retv, inlen, "%s", buf);
4479 }
4480 }
4481
4482 return fulllen;
4483 }
4484
4485 /* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
4486 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
4487 * entries will be printed, in 'lxc.sysctl.key = value' format.
4488 */
4489 static int get_config_sysctl(const char *key, char *retv, int inlen,
4490 struct lxc_conf *c, void *data)
4491 {
4492 int len;
4493 struct lxc_list *it;
4494 int fulllen = 0;
4495 bool get_all = false;
4496
4497 if (!retv)
4498 inlen = 0;
4499 else
4500 memset(retv, 0, inlen);
4501
4502 if (strcmp(key, "lxc.sysctl") == 0)
4503 get_all = true;
4504 else if (strncmp(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")) == 0)
4505 key += STRLITERALLEN("lxc.sysctl.");
4506 else
4507 return -1;
4508
4509 lxc_list_for_each(it, &c->sysctls) {
4510 struct lxc_sysctl *elem = it->elem;
4511 if (get_all) {
4512 strprint(retv, inlen, "lxc.sysctl.%s = %s\n", elem->key,
4513 elem->value);
4514 } else if (strcmp(elem->key, key) == 0) {
4515 strprint(retv, inlen, "%s", elem->value);
4516 }
4517 }
4518
4519 return fulllen;
4520 }
4521
4522 static int get_config_proc(const char *key, char *retv, int inlen,
4523 struct lxc_conf *c, void *data)
4524 {
4525 struct lxc_list *it;
4526 int len;
4527 int fulllen = 0;
4528 bool get_all = false;
4529
4530 if (!retv)
4531 inlen = 0;
4532 else
4533 memset(retv, 0, inlen);
4534
4535 if (strcmp(key, "lxc.proc") == 0)
4536 get_all = true;
4537 else if (strncmp(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")) == 0)
4538 key += STRLITERALLEN("lxc.proc.");
4539 else
4540 return -1;
4541
4542 lxc_list_for_each(it, &c->procs) {
4543 struct lxc_proc *proc = it->elem;
4544
4545 if (get_all) {
4546 strprint(retv, inlen, "lxc.proc.%s = %s\n",
4547 proc->filename, proc->value);
4548 } else if (strcmp(proc->filename, key) == 0) {
4549 strprint(retv, inlen, "%s", proc->value);
4550 }
4551 }
4552
4553 return fulllen;
4554 }
4555
4556 static int get_config_namespace_clone(const char *key, char *retv, int inlen,
4557 struct lxc_conf *c, void *data)
4558 {
4559 int i, len;
4560 int fulllen = 0;
4561
4562 if (!retv)
4563 inlen = 0;
4564 else
4565 memset(retv, 0, inlen);
4566
4567 for (i = 0; i < LXC_NS_MAX; i++) {
4568 if (c->ns_clone & ns_info[i].clone_flag)
4569 strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
4570 }
4571
4572 return fulllen;
4573 }
4574
4575 static int get_config_namespace_keep(const char *key, char *retv, int inlen,
4576 struct lxc_conf *c, void *data)
4577 {
4578 int i, len;
4579 int fulllen = 0;
4580
4581 if (!retv)
4582 inlen = 0;
4583 else
4584 memset(retv, 0, inlen);
4585
4586 for (i = 0; i < LXC_NS_MAX; i++) {
4587 if (c->ns_keep & ns_info[i].clone_flag)
4588 strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
4589 }
4590
4591 return fulllen;
4592 }
4593
4594 static int get_config_time_offset_boot(const char *key, char *retv, int inlen, struct lxc_conf *c,
4595 void *data)
4596 {
4597 int len;
4598 int fulllen = 0;
4599
4600 if (!retv)
4601 inlen = 0;
4602 else
4603 memset(retv, 0, inlen);
4604
4605 if (c->timens.s_boot) {
4606 strprint(retv, inlen, "%" PRId64 " s\n", c->timens.s_boot);
4607 } else {
4608 strprint(retv, inlen, "%" PRId64 " ns\n", c->timens.ns_boot);
4609 }
4610
4611 return fulllen;
4612 }
4613
4614 static int get_config_time_offset_monotonic(const char *key, char *retv, int inlen,
4615 struct lxc_conf *c, void *data)
4616 {
4617 int len;
4618 int fulllen = 0;
4619
4620 if (!retv)
4621 inlen = 0;
4622 else
4623 memset(retv, 0, inlen);
4624
4625 if (c->timens.s_monotonic) {
4626 strprint(retv, inlen, "%" PRId64 "s\n", c->timens.s_monotonic);
4627 } else {
4628 strprint(retv, inlen, "%" PRId64 "ns\n", c->timens.ns_monotonic);
4629 }
4630
4631 return fulllen;
4632 }
4633
4634 static int get_config_namespace_share(const char *key, char *retv, int inlen,
4635 struct lxc_conf *c, void *data)
4636 {
4637 int len, ns_idx;
4638 const char *namespace;
4639 int fulllen = 0;
4640
4641 if (!retv)
4642 inlen = 0;
4643 else
4644 memset(retv, 0, inlen);
4645
4646 namespace = key + STRLITERALLEN("lxc.namespace.share.");
4647 ns_idx = lxc_namespace_2_ns_idx(namespace);
4648 if (ns_idx < 0)
4649 return ns_idx;
4650
4651 strprint(retv, inlen, "%s", c->ns_share[ns_idx]);
4652
4653 return fulllen;
4654 }
4655
4656 /* Callbacks to clear config items. */
4657 static inline int clr_config_personality(const char *key, struct lxc_conf *c,
4658 void *data)
4659 {
4660 c->personality = -1;
4661 return 0;
4662 }
4663
4664 static inline int clr_config_pty_max(const char *key, struct lxc_conf *c,
4665 void *data)
4666 {
4667 c->pty_max = 0;
4668 return 0;
4669 }
4670
4671 static inline int clr_config_tty_max(const char *key, struct lxc_conf *c,
4672 void *data)
4673 {
4674 c->ttys.tty = 0;
4675 return 0;
4676 }
4677
4678 static inline int clr_config_tty_dir(const char *key, struct lxc_conf *c,
4679 void *data)
4680 {
4681 free(c->ttys.dir);
4682 c->ttys.dir = NULL;
4683 return 0;
4684 }
4685
4686 static inline int clr_config_apparmor_profile(const char *key,
4687 struct lxc_conf *c, void *data)
4688 {
4689 free(c->lsm_aa_profile);
4690 c->lsm_aa_profile = NULL;
4691 return 0;
4692 }
4693
4694 static inline int clr_config_apparmor_allow_incomplete(const char *key,
4695 struct lxc_conf *c,
4696 void *data)
4697 {
4698 c->lsm_aa_allow_incomplete = 0;
4699 return 0;
4700 }
4701
4702 static inline int clr_config_apparmor_allow_nesting(const char *key,
4703 struct lxc_conf *c,
4704 void *data)
4705 {
4706 c->lsm_aa_allow_nesting = 0;
4707 return 0;
4708 }
4709
4710 static inline int clr_config_apparmor_raw(const char *key,
4711 struct lxc_conf *c,
4712 void *data)
4713 {
4714 return lxc_clear_apparmor_raw(c);
4715 }
4716
4717 static inline int clr_config_selinux_context(const char *key,
4718 struct lxc_conf *c, void *data)
4719 {
4720 free(c->lsm_se_context);
4721 c->lsm_se_context = NULL;
4722 return 0;
4723 }
4724
4725 static inline int clr_config_selinux_context_keyring(const char *key,
4726 struct lxc_conf *c, void *data)
4727 {
4728 free(c->lsm_se_keyring_context);
4729 c->lsm_se_keyring_context = NULL;
4730 return 0;
4731 }
4732
4733 static inline int clr_config_keyring_session(const char *key,
4734 struct lxc_conf *c, void *data)
4735 {
4736 c->keyring_disable_session = false;
4737 return 0;
4738 }
4739
4740 static inline int clr_config_cgroup_controller(const char *key,
4741 struct lxc_conf *c, void *data)
4742 {
4743 return lxc_clear_cgroups(c, key, CGROUP_SUPER_MAGIC);
4744 }
4745
4746 static inline int clr_config_cgroup2_controller(const char *key,
4747 struct lxc_conf *c, void *data)
4748 {
4749 return lxc_clear_cgroups(c, key, CGROUP2_SUPER_MAGIC);
4750 }
4751
4752 static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
4753 void *data)
4754 {
4755 if (lxc_conf->cgroup_meta.dir) {
4756 free(lxc_conf->cgroup_meta.dir);
4757 lxc_conf->cgroup_meta.dir = NULL;
4758 }
4759
4760 return 0;
4761 }
4762
4763 static int clr_config_cgroup_monitor_dir(const char *key,
4764 struct lxc_conf *lxc_conf,
4765 void *data)
4766 {
4767 free_disarm(lxc_conf->cgroup_meta.monitor_dir);
4768 return 0;
4769 }
4770
4771 static int clr_config_cgroup_container_dir(const char *key,
4772 struct lxc_conf *lxc_conf,
4773 void *data)
4774 {
4775 free_disarm(lxc_conf->cgroup_meta.container_dir);
4776 return 0;
4777 }
4778
4779 static int clr_config_cgroup_container_inner_dir(const char *key,
4780 struct lxc_conf *lxc_conf,
4781 void *data)
4782 {
4783 free_disarm(lxc_conf->cgroup_meta.namespace_dir);
4784 return 0;
4785 }
4786
4787 static inline int clr_config_cgroup_relative(const char *key,
4788 struct lxc_conf *lxc_conf,
4789 void *data)
4790 {
4791 lxc_conf->cgroup_meta.relative = false;
4792 return 0;
4793 }
4794
4795 static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
4796 void *data)
4797 {
4798 return lxc_clear_idmaps(c);
4799 }
4800
4801 static inline int clr_config_log_level(const char *key, struct lxc_conf *c,
4802 void *data)
4803 {
4804 c->loglevel = LXC_LOG_LEVEL_NOTSET;
4805 return 0;
4806 }
4807
4808 static inline int clr_config_log_file(const char *key, struct lxc_conf *c,
4809 void *data)
4810 {
4811 free(c->logfile);
4812 c->logfile = NULL;
4813 return 0;
4814 }
4815
4816 static inline int clr_config_mount(const char *key, struct lxc_conf *c,
4817 void *data)
4818 {
4819 return lxc_clear_mount_entries(c);
4820 }
4821
4822 static inline int clr_config_mount_auto(const char *key, struct lxc_conf *c,
4823 void *data)
4824 {
4825 return lxc_clear_automounts(c);
4826 }
4827
4828 static inline int clr_config_mount_fstab(const char *key, struct lxc_conf *c,
4829 void *data)
4830 {
4831 free(c->fstab);
4832 c->fstab = NULL;
4833 return 0;
4834 }
4835
4836 static inline int clr_config_rootfs_path(const char *key, struct lxc_conf *c,
4837 void *data)
4838 {
4839 free(c->rootfs.path);
4840 c->rootfs.path = NULL;
4841 return 0;
4842 }
4843
4844 static inline int clr_config_rootfs_managed(const char *key, struct lxc_conf *c,
4845 void *data)
4846 {
4847 c->rootfs.managed = true;
4848 return 0;
4849 }
4850
4851 static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
4852 void *data)
4853 {
4854 free(c->rootfs.mount);
4855 c->rootfs.mount = NULL;
4856 return 0;
4857 }
4858
4859 static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
4860 void *data)
4861 {
4862 free(c->rootfs.options);
4863 c->rootfs.options = NULL;
4864
4865 free(c->rootfs.data);
4866 c->rootfs.data = NULL;
4867
4868 return 0;
4869 }
4870
4871 static inline int clr_config_uts_name(const char *key, struct lxc_conf *c,
4872 void *data)
4873 {
4874 free(c->utsname);
4875 c->utsname = NULL;
4876 return 0;
4877 }
4878
4879 static inline int clr_config_hooks(const char *key, struct lxc_conf *c,
4880 void *data)
4881 {
4882 return lxc_clear_hooks(c, key);
4883 }
4884
4885 static inline int clr_config_hooks_version(const char *key, struct lxc_conf *c,
4886 void *data)
4887 {
4888 /* default to legacy hooks version */
4889 c->hooks_version = 0;
4890 return 0;
4891 }
4892
4893 static inline int clr_config_net(const char *key, struct lxc_conf *c,
4894 void *data)
4895 {
4896 lxc_free_networks(&c->network);
4897
4898 return 0;
4899 }
4900
4901 static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c,
4902 void *data)
4903 {
4904 return lxc_clear_config_caps(c);
4905 }
4906
4907 static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
4908 void *data)
4909 {
4910 return lxc_clear_config_keepcaps(c);
4911 }
4912
4913 static inline int clr_config_console_path(const char *key, struct lxc_conf *c,
4914 void *data)
4915 {
4916 free(c->console.path);
4917 c->console.path = NULL;
4918 return 0;
4919 }
4920
4921 static inline int clr_config_console_logfile(const char *key,
4922 struct lxc_conf *c, void *data)
4923 {
4924 free(c->console.log_path);
4925 c->console.log_path = NULL;
4926 return 0;
4927 }
4928
4929 static inline int clr_config_console_rotate(const char *key, struct lxc_conf *c,
4930 void *data)
4931 {
4932 c->console.log_rotate = 0;
4933 return 0;
4934 }
4935
4936 static inline int clr_config_console_buffer_size(const char *key,
4937 struct lxc_conf *c, void *data)
4938 {
4939 c->console.buffer_size = 0;
4940 return 0;
4941 }
4942
4943 static inline int clr_config_console_size(const char *key, struct lxc_conf *c,
4944 void *data)
4945 {
4946 c->console.log_size = 0;
4947 return 0;
4948 }
4949
4950 static inline int clr_config_seccomp_allow_nesting(const char *key,
4951 struct lxc_conf *c, void *data)
4952 {
4953 #ifdef HAVE_SECCOMP
4954 c->seccomp.allow_nesting = 0;
4955 return 0;
4956 #else
4957 errno = ENOSYS;
4958 return -1;
4959 #endif
4960 }
4961
4962 static inline int clr_config_seccomp_notify_cookie(const char *key,
4963 struct lxc_conf *c, void *data)
4964 {
4965 #ifdef HAVE_SECCOMP_NOTIFY
4966 free(c->seccomp.notifier.cookie);
4967 c->seccomp.notifier.cookie = NULL;
4968 return 0;
4969 #else
4970 return ret_set_errno(-1, ENOSYS);
4971 #endif
4972 }
4973
4974 static inline int clr_config_seccomp_notify_proxy(const char *key,
4975 struct lxc_conf *c, void *data)
4976 {
4977 #ifdef HAVE_SECCOMP_NOTIFY
4978 memset(&c->seccomp.notifier.proxy_addr, 0,
4979 sizeof(c->seccomp.notifier.proxy_addr));
4980 return 0;
4981 #else
4982 return ret_set_errno(-1, ENOSYS);
4983 #endif
4984 }
4985
4986 static inline int clr_config_seccomp_profile(const char *key,
4987 struct lxc_conf *c, void *data)
4988 {
4989 free(c->seccomp.seccomp);
4990 c->seccomp.seccomp = NULL;
4991 return 0;
4992 }
4993
4994 static inline int clr_config_autodev(const char *key, struct lxc_conf *c,
4995 void *data)
4996 {
4997 c->autodev = 1;
4998 return 0;
4999 }
5000
5001 static inline int clr_config_autodev_tmpfs_size(const char *key, struct lxc_conf *c,
5002 void *data)
5003 {
5004 c->autodevtmpfssize = 500000;
5005 return 0;
5006 }
5007
5008 static inline int clr_config_signal_halt(const char *key, struct lxc_conf *c,
5009 void *data)
5010 {
5011 c->haltsignal = 0;
5012 return 0;
5013 }
5014
5015 static inline int clr_config_signal_reboot(const char *key, struct lxc_conf *c,
5016 void *data)
5017 {
5018 c->rebootsignal = 0;
5019 return 0;
5020 }
5021
5022 static inline int clr_config_signal_stop(const char *key, struct lxc_conf *c,
5023 void *data)
5024 {
5025 c->stopsignal = 0;
5026 return 0;
5027 }
5028
5029 static inline int clr_config_start(const char *key, struct lxc_conf *c,
5030 void *data)
5031 {
5032 if (strcmp(key + 10, "auto") == 0)
5033 c->start_auto = 0;
5034 else if (strcmp(key + 10, "delay") == 0)
5035 c->start_delay = 0;
5036 else if (strcmp(key + 10, "order") == 0)
5037 c->start_order = 0;
5038
5039 return 0;
5040 }
5041
5042 static inline int clr_config_log_syslog(const char *key, struct lxc_conf *c,
5043 void *data)
5044 {
5045 free(c->syslog);
5046 c->syslog = NULL;
5047 return 0;
5048 }
5049
5050 static inline int clr_config_monitor(const char *key, struct lxc_conf *c,
5051 void *data)
5052 {
5053 c->monitor_unshare = 0;
5054 return 0;
5055 }
5056
5057 static inline int clr_config_monitor_signal_pdeath(const char *key,
5058 struct lxc_conf *c, void *data)
5059 {
5060 c->monitor_signal_pdeath = 0;
5061 return 0;
5062 }
5063
5064 static inline int clr_config_group(const char *key, struct lxc_conf *c,
5065 void *data)
5066 {
5067 return lxc_clear_groups(c);
5068 }
5069
5070 static inline int clr_config_environment(const char *key, struct lxc_conf *c,
5071 void *data)
5072 {
5073 return lxc_clear_environment(c);
5074 }
5075
5076 static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
5077 void *data)
5078 {
5079 free(c->execute_cmd);
5080 c->execute_cmd = NULL;
5081 return 0;
5082 }
5083
5084 static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
5085 void *data)
5086 {
5087 free(c->init_cmd);
5088 c->init_cmd = NULL;
5089 return 0;
5090 }
5091
5092 static inline int clr_config_init_cwd(const char *key, struct lxc_conf *c,
5093 void *data)
5094 {
5095 free(c->init_cwd);
5096 c->init_cwd = NULL;
5097 return 0;
5098 }
5099
5100 static inline int clr_config_init_uid(const char *key, struct lxc_conf *c,
5101 void *data)
5102 {
5103 c->init_uid = 0;
5104 return 0;
5105 }
5106
5107 static inline int clr_config_init_gid(const char *key, struct lxc_conf *c,
5108 void *data)
5109 {
5110 c->init_gid = 0;
5111 return 0;
5112 }
5113
5114 static inline int clr_config_ephemeral(const char *key, struct lxc_conf *c,
5115 void *data)
5116 {
5117 c->ephemeral = 0;
5118 return 0;
5119 }
5120
5121 static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c,
5122 void *data)
5123 {
5124 c->no_new_privs = false;
5125 return 0;
5126 }
5127
5128 static inline int clr_config_prlimit(const char *key, struct lxc_conf *c,
5129 void *data)
5130 {
5131 return lxc_clear_limits(c, key);
5132 }
5133
5134 static inline int clr_config_sysctl(const char *key, struct lxc_conf *c,
5135 void *data)
5136 {
5137 return lxc_clear_sysctls(c, key);
5138 }
5139
5140 static inline int clr_config_proc(const char *key, struct lxc_conf *c,
5141 void *data)
5142 {
5143 return lxc_clear_procs(c, key);
5144 }
5145
5146 static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
5147 void *data)
5148 {
5149 lxc_clear_includes(c);
5150 return 0;
5151 }
5152
5153 static int clr_config_namespace_clone(const char *key,
5154 struct lxc_conf *lxc_conf, void *data)
5155 {
5156 lxc_conf->ns_clone = 0;
5157 return 0;
5158 }
5159
5160 static int clr_config_namespace_keep(const char *key, struct lxc_conf *lxc_conf,
5161 void *data)
5162 {
5163 lxc_conf->ns_keep = 0;
5164 return 0;
5165 }
5166
5167 static int clr_config_time_offset_boot(const char *key, struct lxc_conf *lxc_conf, void *data)
5168 {
5169 lxc_conf->timens.s_boot = 0;
5170 lxc_conf->timens.ns_boot = 0;
5171 return 0;
5172 }
5173
5174 static int clr_config_time_offset_monotonic(const char *key, struct lxc_conf *lxc_conf, void *data)
5175 {
5176 lxc_conf->timens.s_monotonic = 0;
5177 lxc_conf->timens.ns_monotonic = 0;
5178 return 0;
5179 }
5180
5181 static int clr_config_namespace_share(const char *key,
5182 struct lxc_conf *lxc_conf, void *data)
5183 {
5184 int ns_idx;
5185 const char *namespace;
5186
5187 namespace = key + STRLITERALLEN("lxc.namespace.share.");
5188 ns_idx = lxc_namespace_2_ns_idx(namespace);
5189 if (ns_idx < 0)
5190 return ns_idx;
5191
5192 free(lxc_conf->ns_share[ns_idx]);
5193 lxc_conf->ns_share[ns_idx] = NULL;
5194
5195 return 0;
5196 }
5197
5198 static int get_config_includefiles(const char *key, char *retv, int inlen,
5199 struct lxc_conf *c, void *data)
5200 {
5201 return -ENOSYS;
5202 }
5203
5204 static struct lxc_config_t *get_network_config_ops(const char *key,
5205 struct lxc_conf *lxc_conf,
5206 ssize_t *idx,
5207 char **deindexed_key)
5208 {
5209 int ret;
5210 unsigned int tmpidx;
5211 size_t numstrlen;
5212 char *copy, *idx_start, *idx_end;
5213 struct lxc_config_t *config = NULL;
5214
5215 /* check that this is a sensible network key */
5216 if (strncmp("lxc.net.", key, 8)) {
5217 ERROR("Invalid network configuration key \"%s\"", key);
5218 return NULL;
5219 }
5220
5221 copy = strdup(key);
5222 if (!copy) {
5223 ERROR("Failed to duplicate string \"%s\"", key);
5224 return NULL;
5225 }
5226
5227 /* lxc.net.<n> */
5228 if (!isdigit(*(key + 8))) {
5229 ERROR("Failed to detect digit in string \"%s\"", key + 8);
5230 goto on_error;
5231 }
5232
5233 /* beginning of index string */
5234 idx_start = (copy + 7);
5235 *idx_start = '\0';
5236
5237 /* end of index string */
5238 idx_end = strchr((copy + 8), '.');
5239 if (idx_end)
5240 *idx_end = '\0';
5241
5242 /* parse current index */
5243 ret = lxc_safe_uint((idx_start + 1), &tmpidx);
5244 if (ret < 0) {
5245 errno = -ret;
5246 SYSERROR("Failed to parse unsigned integer from string \"%s\"",
5247 idx_start + 1);
5248 *idx = ret;
5249 goto on_error;
5250 }
5251
5252 /* This, of course is utterly nonsensical on so many levels, but
5253 * better safe than sorry.
5254 * (Checking for INT_MAX here is intentional.)
5255 */
5256 if (tmpidx == INT_MAX) {
5257 SYSERROR("Number of configured networks would overflow the "
5258 "counter");
5259 goto on_error;
5260 }
5261 *idx = tmpidx;
5262
5263 numstrlen = strlen((idx_start + 1));
5264
5265 /* repair configuration key */
5266 *idx_start = '.';
5267
5268 /* lxc.net.<idx>.<subkey> */
5269 if (idx_end) {
5270 *idx_end = '.';
5271 if (strlen(idx_end + 1) == 0) {
5272 ERROR("No subkey in network configuration key \"%s\"", key);
5273 goto on_error;
5274 }
5275
5276 memmove(copy + 8, idx_end + 1, strlen(idx_end + 1));
5277 copy[strlen(key) - (numstrlen + 1)] = '\0';
5278
5279 config = lxc_get_config(copy);
5280 if (!config) {
5281 ERROR("Unknown network configuration key \"%s\"", key);
5282 goto on_error;
5283 }
5284 }
5285
5286 if (deindexed_key)
5287 *deindexed_key = copy;
5288
5289 return config;
5290
5291 on_error:
5292 free(copy);
5293 return NULL;
5294 }
5295
5296 /* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
5297 * found. So we make sure next comes an integer, find the right callback (by
5298 * rewriting the key), and call it.
5299 */
5300 static int set_config_net_nic(const char *key, const char *value,
5301 struct lxc_conf *lxc_conf, void *data)
5302 {
5303 int ret;
5304 const char *idxstring;
5305 struct lxc_config_t *config;
5306 struct lxc_netdev *netdev;
5307 ssize_t idx = -1;
5308 char *deindexed_key = NULL;
5309
5310 idxstring = key + 8;
5311 if (!isdigit(*idxstring))
5312 return -1;
5313
5314 if (lxc_config_value_empty(value))
5315 return clr_config_net_nic(key, lxc_conf, data);
5316
5317 config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
5318 if (!config || idx < 0)
5319 return -1;
5320
5321 netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true);
5322 if (!netdev) {
5323 free(deindexed_key);
5324 return -1;
5325 }
5326
5327 ret = config->set(deindexed_key, value, lxc_conf, netdev);
5328 free(deindexed_key);
5329
5330 return ret;
5331 }
5332
5333 static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
5334 void *data)
5335 {
5336 int ret;
5337 const char *idxstring;
5338 struct lxc_config_t *config;
5339 struct lxc_netdev *netdev;
5340 ssize_t idx = -1;
5341 char *deindexed_key = NULL;
5342
5343 idxstring = key + 8;
5344 if (!isdigit(*idxstring))
5345 return -1;
5346
5347 /* The left conjunct is pretty self-explanatory. The right conjunct
5348 * checks whether the two pointers are equal. If they are we know that
5349 * this is not a key that is namespaced any further and so we are
5350 * supposed to clear the whole network.
5351 */
5352 if (isdigit(*idxstring) && (strrchr(key, '.') == (idxstring - 1))) {
5353 unsigned int rmnetdevidx;
5354
5355 if (lxc_safe_uint(idxstring, &rmnetdevidx) < 0)
5356 return -1;
5357
5358 /* Remove network from network list. */
5359 lxc_remove_nic_by_idx(lxc_conf, rmnetdevidx);
5360 return 0;
5361 }
5362
5363 config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
5364 if (!config || idx < 0)
5365 return -1;
5366
5367 netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false);
5368 if (!netdev) {
5369 free(deindexed_key);
5370 return -1;
5371 }
5372
5373 ret = config->clr(deindexed_key, lxc_conf, netdev);
5374 free(deindexed_key);
5375
5376 return ret;
5377 }
5378
5379 static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
5380 void *data)
5381 {
5382 struct lxc_netdev *netdev = data;
5383
5384 if (!netdev)
5385 return -1;
5386
5387 netdev->type = -1;
5388
5389 return 0;
5390 }
5391
5392 static int clr_config_net_name(const char *key, struct lxc_conf *lxc_conf,
5393 void *data)
5394 {
5395 struct lxc_netdev *netdev = data;
5396
5397 if (!netdev)
5398 return -1;
5399
5400 netdev->name[0] = '\0';
5401
5402 return 0;
5403 }
5404
5405 static int clr_config_net_flags(const char *key, struct lxc_conf *lxc_conf,
5406 void *data)
5407 {
5408 struct lxc_netdev *netdev = data;
5409
5410 if (!netdev)
5411 return -1;
5412
5413 netdev->flags = 0;
5414
5415 return 0;
5416 }
5417
5418 static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
5419 void *data)
5420 {
5421 struct lxc_netdev *netdev = data;
5422
5423 if (!netdev)
5424 return -1;
5425
5426 netdev->link[0] = '\0';
5427
5428 return 0;
5429 }
5430
5431 static int clr_config_net_l2proxy(const char *key, struct lxc_conf *lxc_conf,
5432 void *data)
5433 {
5434 struct lxc_netdev *netdev = data;
5435
5436 if (!netdev)
5437 return ret_set_errno(-1, EINVAL);
5438
5439 netdev->l2proxy = false;
5440
5441 return 0;
5442 }
5443
5444 static int clr_config_net_macvlan_mode(const char *key,
5445 struct lxc_conf *lxc_conf, void *data)
5446 {
5447 struct lxc_netdev *netdev = data;
5448
5449 if (!netdev)
5450 return -1;
5451
5452 if (netdev->type != LXC_NET_MACVLAN)
5453 return 0;
5454
5455 netdev->priv.macvlan_attr.mode = -1;
5456
5457 return 0;
5458 }
5459
5460 static int clr_config_net_ipvlan_mode(const char *key,
5461 struct lxc_conf *lxc_conf, void *data)
5462 {
5463 struct lxc_netdev *netdev = data;
5464
5465 if (!netdev)
5466 return ret_set_errno(-1, EINVAL);
5467
5468 if (netdev->type != LXC_NET_IPVLAN)
5469 return 0;
5470
5471 netdev->priv.ipvlan_attr.mode = -1;
5472
5473 return 0;
5474 }
5475
5476 static int clr_config_net_ipvlan_isolation(const char *key,
5477 struct lxc_conf *lxc_conf, void *data)
5478 {
5479 struct lxc_netdev *netdev = data;
5480
5481 if (!netdev)
5482 return ret_set_errno(-1, EINVAL);
5483
5484 if (netdev->type != LXC_NET_IPVLAN)
5485 return 0;
5486
5487 netdev->priv.ipvlan_attr.isolation = -1;
5488
5489 return 0;
5490 }
5491
5492 static int clr_config_net_veth_mode(const char *key,
5493 struct lxc_conf *lxc_conf, void *data)
5494 {
5495 struct lxc_netdev *netdev = data;
5496
5497 if (!netdev)
5498 return ret_set_errno(-1, EINVAL);
5499
5500 if (netdev->type != LXC_NET_VETH)
5501 return 0;
5502
5503 netdev->priv.veth_attr.mode = -1;
5504
5505 return 0;
5506 }
5507
5508 static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
5509 void *data)
5510 {
5511 struct lxc_netdev *netdev = data;
5512
5513 if (!netdev)
5514 return -1;
5515
5516 netdev->priv.veth_attr.pair[0] = '\0';
5517
5518 return 0;
5519 }
5520
5521 static int clr_config_net_veth_vlan_id(const char *key, struct lxc_conf *lxc_conf,
5522 void *data)
5523 {
5524 struct lxc_netdev *netdev = data;
5525
5526 if (!netdev)
5527 return ret_errno(EINVAL);
5528
5529 netdev->priv.veth_attr.vlan_id = 0;
5530 netdev->priv.veth_attr.vlan_id_set = false;
5531
5532 return 0;
5533 }
5534
5535 static int clr_config_net_veth_vlan_tagged_id(const char *key,
5536 struct lxc_conf *lxc_conf, void *data)
5537 {
5538 struct lxc_netdev *netdev = data;
5539 struct lxc_list *cur, *next;
5540
5541 if (!netdev)
5542 return ret_errno(EINVAL);
5543
5544 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
5545 lxc_list_del(cur);
5546 free(cur);
5547 }
5548
5549 return 0;
5550 }
5551
5552
5553 static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
5554 void *data)
5555 {
5556 struct lxc_netdev *netdev = data;
5557
5558 if (!netdev)
5559 return -1;
5560
5561 free(netdev->upscript);
5562 netdev->upscript = NULL;
5563
5564 return 0;
5565 }
5566
5567 static int clr_config_net_script_down(const char *key,
5568 struct lxc_conf *lxc_conf, void *data)
5569 {
5570 struct lxc_netdev *netdev = data;
5571
5572 if (!netdev)
5573 return -1;
5574
5575 free(netdev->downscript);
5576 netdev->downscript = NULL;
5577
5578 return 0;
5579 }
5580
5581 static int clr_config_net_hwaddr(const char *key, struct lxc_conf *lxc_conf,
5582 void *data)
5583 {
5584 struct lxc_netdev *netdev = data;
5585
5586 if (!netdev)
5587 return -1;
5588
5589 free(netdev->hwaddr);
5590 netdev->hwaddr = NULL;
5591
5592 return 0;
5593 }
5594
5595 static int clr_config_net_mtu(const char *key, struct lxc_conf *lxc_conf,
5596 void *data)
5597 {
5598 struct lxc_netdev *netdev = data;
5599
5600 if (!netdev)
5601 return -1;
5602
5603 free(netdev->mtu);
5604 netdev->mtu = NULL;
5605
5606 return 0;
5607 }
5608
5609 static int clr_config_net_vlan_id(const char *key, struct lxc_conf *lxc_conf,
5610 void *data)
5611 {
5612 struct lxc_netdev *netdev = data;
5613
5614 if (!netdev)
5615 return -1;
5616
5617 netdev->priv.vlan_attr.vid = 0;
5618
5619 return 0;
5620 }
5621
5622 static int clr_config_net_ipv4_gateway(const char *key,
5623 struct lxc_conf *lxc_conf, void *data)
5624 {
5625 struct lxc_netdev *netdev = data;
5626
5627 if (!netdev)
5628 return -1;
5629
5630 free(netdev->ipv4_gateway);
5631 netdev->ipv4_gateway = NULL;
5632
5633 return 0;
5634 }
5635
5636 static int clr_config_net_ipv4_address(const char *key,
5637 struct lxc_conf *lxc_conf, void *data)
5638 {
5639 struct lxc_netdev *netdev = data;
5640 struct lxc_list *cur, *next;
5641
5642 if (!netdev)
5643 return -1;
5644
5645 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
5646 lxc_list_del(cur);
5647 free(cur->elem);
5648 free(cur);
5649 }
5650
5651 return 0;
5652 }
5653
5654 static int clr_config_net_veth_ipv4_route(const char *key,
5655 struct lxc_conf *lxc_conf, void *data)
5656 {
5657 struct lxc_netdev *netdev = data;
5658 struct lxc_list *cur, *next;
5659
5660 if (!netdev)
5661 return -1;
5662
5663 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
5664 lxc_list_del(cur);
5665 free(cur->elem);
5666 free(cur);
5667 }
5668
5669 return 0;
5670 }
5671
5672 static int clr_config_net_ipv6_gateway(const char *key,
5673 struct lxc_conf *lxc_conf, void *data)
5674 {
5675 struct lxc_netdev *netdev = data;
5676
5677 if (!netdev)
5678 return -1;
5679
5680 free(netdev->ipv6_gateway);
5681 netdev->ipv6_gateway = NULL;
5682
5683 return 0;
5684 }
5685
5686 static int clr_config_net_ipv6_address(const char *key,
5687 struct lxc_conf *lxc_conf, void *data)
5688 {
5689 struct lxc_netdev *netdev = data;
5690 struct lxc_list *cur, *next;
5691
5692 if (!netdev)
5693 return -1;
5694
5695 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
5696 lxc_list_del(cur);
5697 free(cur->elem);
5698 free(cur);
5699 }
5700
5701 return 0;
5702 }
5703
5704 static int clr_config_net_veth_ipv6_route(const char *key,
5705 struct lxc_conf *lxc_conf, void *data)
5706 {
5707 struct lxc_netdev *netdev = data;
5708 struct lxc_list *cur, *next;
5709
5710 if (!netdev)
5711 return -1;
5712
5713 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
5714 lxc_list_del(cur);
5715 free(cur->elem);
5716 free(cur);
5717 }
5718
5719 return 0;
5720 }
5721
5722 static int get_config_net_nic(const char *key, char *retv, int inlen,
5723 struct lxc_conf *c, void *data)
5724 {
5725 int ret;
5726 const char *idxstring;
5727 struct lxc_config_t *config;
5728 struct lxc_netdev *netdev;
5729 ssize_t idx = -1;
5730 char *deindexed_key = NULL;
5731
5732 idxstring = key + 8;
5733 if (!isdigit(*idxstring))
5734 return -1;
5735
5736 config = get_network_config_ops(key, c, &idx, &deindexed_key);
5737 if (!config || idx < 0)
5738 return -1;
5739
5740 netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
5741 if (!netdev) {
5742 free(deindexed_key);
5743 return -1;
5744 }
5745
5746 ret = config->get(deindexed_key, retv, inlen, c, netdev);
5747 free(deindexed_key);
5748
5749 return ret;
5750 }
5751
5752 static int get_config_net_type(const char *key, char *retv, int inlen,
5753 struct lxc_conf *c, void *data)
5754 {
5755 int len;
5756 int fulllen = 0;
5757 struct lxc_netdev *netdev = data;
5758
5759 if (!retv)
5760 inlen = 0;
5761 else
5762 memset(retv, 0, inlen);
5763
5764 if (!netdev)
5765 return -1;
5766
5767 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
5768
5769 return fulllen;
5770 }
5771
5772 static int get_config_net_flags(const char *key, char *retv, int inlen,
5773 struct lxc_conf *c, void *data)
5774 {
5775 int len;
5776 int fulllen = 0;
5777 struct lxc_netdev *netdev = data;
5778
5779 if (!retv)
5780 inlen = 0;
5781 else
5782 memset(retv, 0, inlen);
5783
5784 if (!netdev)
5785 return -1;
5786
5787 if (netdev->flags & IFF_UP)
5788 strprint(retv, inlen, "up");
5789
5790 return fulllen;
5791 }
5792
5793 static int get_config_net_link(const char *key, char *retv, int inlen,
5794 struct lxc_conf *c, void *data)
5795 {
5796 int len;
5797 int fulllen = 0;
5798 struct lxc_netdev *netdev = data;
5799
5800 if (!retv)
5801 inlen = 0;
5802 else
5803 memset(retv, 0, inlen);
5804
5805 if (!netdev)
5806 return -1;
5807
5808 if (netdev->link[0] != '\0')
5809 strprint(retv, inlen, "%s", netdev->link);
5810
5811 return fulllen;
5812 }
5813
5814 static int get_config_net_l2proxy(const char *key, char *retv, int inlen,
5815 struct lxc_conf *c, void *data)
5816 {
5817 struct lxc_netdev *netdev = data;
5818 return lxc_get_conf_bool(c, retv, inlen, netdev->l2proxy);
5819 }
5820
5821 static int get_config_net_name(const char *key, char *retv, int inlen,
5822 struct lxc_conf *c, void *data)
5823 {
5824 int len;
5825 int fulllen = 0;
5826 struct lxc_netdev *netdev = data;
5827
5828 if (!retv)
5829 inlen = 0;
5830 else
5831 memset(retv, 0, inlen);
5832
5833 if (!netdev)
5834 return -1;
5835
5836 if (netdev->name[0] != '\0')
5837 strprint(retv, inlen, "%s", netdev->name);
5838
5839 return fulllen;
5840 }
5841
5842 static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
5843 struct lxc_conf *c, void *data)
5844 {
5845 int len;
5846 int fulllen = 0;
5847 const char *mode;
5848 struct lxc_netdev *netdev = data;
5849
5850 if (!retv)
5851 inlen = 0;
5852 else
5853 memset(retv, 0, inlen);
5854
5855 if (!netdev)
5856 return -1;
5857
5858 if (netdev->type != LXC_NET_MACVLAN)
5859 return 0;
5860
5861 switch (netdev->priv.macvlan_attr.mode) {
5862 case MACVLAN_MODE_PRIVATE:
5863 mode = "private";
5864 break;
5865 case MACVLAN_MODE_VEPA:
5866 mode = "vepa";
5867 break;
5868 case MACVLAN_MODE_BRIDGE:
5869 mode = "bridge";
5870 break;
5871 case MACVLAN_MODE_PASSTHRU:
5872 mode = "passthru";
5873 break;
5874 default:
5875 mode = "(invalid)";
5876 break;
5877 }
5878
5879 strprint(retv, inlen, "%s", mode);
5880
5881 return fulllen;
5882 }
5883
5884 static int get_config_net_ipvlan_mode(const char *key, char *retv, int inlen,
5885 struct lxc_conf *c, void *data)
5886 {
5887 int len;
5888 int fulllen = 0;
5889 const char *mode;
5890 struct lxc_netdev *netdev = data;
5891
5892 if (!retv)
5893 inlen = 0;
5894 else
5895 memset(retv, 0, inlen);
5896
5897 if (!netdev)
5898 return ret_set_errno(-1, EINVAL);
5899
5900 if (netdev->type != LXC_NET_IPVLAN)
5901 return 0;
5902
5903 switch (netdev->priv.ipvlan_attr.mode) {
5904 case IPVLAN_MODE_L3:
5905 mode = "l3";
5906 break;
5907 case IPVLAN_MODE_L3S:
5908 mode = "l3s";
5909 break;
5910 case IPVLAN_MODE_L2:
5911 mode = "l2";
5912 break;
5913 default:
5914 mode = "(invalid)";
5915 break;
5916 }
5917
5918 strprint(retv, inlen, "%s", mode);
5919
5920 return fulllen;
5921 }
5922
5923 static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inlen,
5924 struct lxc_conf *c, void *data)
5925 {
5926 int len;
5927 int fulllen = 0;
5928 const char *mode;
5929 struct lxc_netdev *netdev = data;
5930
5931 if (!retv)
5932 inlen = 0;
5933 else
5934 memset(retv, 0, inlen);
5935
5936 if (!netdev)
5937 return ret_set_errno(-1, EINVAL);
5938
5939 if (netdev->type != LXC_NET_IPVLAN)
5940 return 0;
5941
5942 switch (netdev->priv.ipvlan_attr.isolation) {
5943 case IPVLAN_ISOLATION_BRIDGE:
5944 mode = "bridge";
5945 break;
5946 case IPVLAN_ISOLATION_PRIVATE:
5947 mode = "private";
5948 break;
5949 case IPVLAN_ISOLATION_VEPA:
5950 mode = "vepa";
5951 break;
5952 default:
5953 mode = "(invalid)";
5954 break;
5955 }
5956
5957 strprint(retv, inlen, "%s", mode);
5958
5959 return fulllen;
5960 }
5961
5962 static int get_config_net_veth_mode(const char *key, char *retv, int inlen,
5963 struct lxc_conf *c, void *data)
5964 {
5965 int len;
5966 int fulllen = 0;
5967 const char *mode;
5968 struct lxc_netdev *netdev = data;
5969
5970 if (!retv)
5971 inlen = 0;
5972 else
5973 memset(retv, 0, inlen);
5974
5975 if (!netdev)
5976 return ret_set_errno(-1, EINVAL);
5977
5978 if (netdev->type != LXC_NET_VETH)
5979 return 0;
5980
5981 switch (netdev->priv.veth_attr.mode) {
5982 case VETH_MODE_BRIDGE:
5983 mode = "bridge";
5984 break;
5985 case VETH_MODE_ROUTER:
5986 mode = "router";
5987 break;
5988 default:
5989 mode = "(invalid)";
5990 break;
5991 }
5992
5993 strprint(retv, inlen, "%s", mode);
5994
5995 return fulllen;
5996 }
5997
5998 static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
5999 struct lxc_conf *c, void *data)
6000 {
6001 int len;
6002 int fulllen = 0;
6003 struct lxc_netdev *netdev = data;
6004
6005 if (!retv)
6006 inlen = 0;
6007 else
6008 memset(retv, 0, inlen);
6009
6010 if (!netdev)
6011 return -1;
6012
6013 if (netdev->type != LXC_NET_VETH)
6014 return 0;
6015
6016 strprint(retv, inlen, "%s",
6017 netdev->priv.veth_attr.pair[0] != '\0'
6018 ? netdev->priv.veth_attr.pair
6019 : netdev->priv.veth_attr.veth1);
6020
6021 return fulllen;
6022 }
6023
6024 static int get_config_net_veth_vlan_id(const char *key, char *retv, int inlen,
6025 struct lxc_conf *c, void *data)
6026 {
6027 int len;
6028 int fulllen = 0;
6029 struct lxc_netdev *netdev = data;
6030
6031 if (!netdev)
6032 return ret_errno(EINVAL);
6033
6034 if (netdev->type != LXC_NET_VETH)
6035 return 0;
6036
6037 if (!retv)
6038 inlen = 0;
6039 else
6040 memset(retv, 0, inlen);
6041
6042 strprint(retv, inlen, "%d", netdev->priv.veth_attr.vlan_id);
6043
6044 return fulllen;
6045 }
6046
6047 static int get_config_net_veth_vlan_tagged_id(const char *key, char *retv, int inlen,
6048 struct lxc_conf *c, void *data)
6049 {
6050 int len;
6051 size_t listlen;
6052 struct lxc_list *it;
6053 int fulllen = 0;
6054 struct lxc_netdev *netdev = data;
6055
6056 if (!netdev)
6057 return ret_errno(EINVAL);
6058
6059 if (netdev->type != LXC_NET_VETH)
6060 return 0;
6061
6062 if (!retv)
6063 inlen = 0;
6064 else
6065 memset(retv, 0, inlen);
6066
6067 listlen = lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids);
6068
6069 lxc_list_for_each(it, &netdev->priv.veth_attr.vlan_tagged_ids) {
6070 unsigned short i = PTR_TO_USHORT(it->elem);
6071 strprint(retv, inlen, "%u%s", i,
6072 (listlen-- > 1) ? "\n" : "");
6073 }
6074
6075 return fulllen;
6076 }
6077
6078 static int get_config_net_script_up(const char *key, char *retv, int inlen,
6079 struct lxc_conf *c, void *data)
6080 {
6081 int len;
6082 int fulllen = 0;
6083 struct lxc_netdev *netdev = data;
6084
6085 if (!retv)
6086 inlen = 0;
6087 else
6088 memset(retv, 0, inlen);
6089
6090 if (!netdev)
6091 return -1;
6092
6093 if (netdev->upscript)
6094 strprint(retv, inlen, "%s", netdev->upscript);
6095
6096 return fulllen;
6097 }
6098
6099 static int get_config_net_script_down(const char *key, char *retv, int inlen,
6100 struct lxc_conf *c, void *data)
6101 {
6102 int len;
6103 int fulllen = 0;
6104 struct lxc_netdev *netdev = data;
6105
6106 if (!retv)
6107 inlen = 0;
6108 else
6109 memset(retv, 0, inlen);
6110
6111 if (!netdev)
6112 return -1;
6113
6114 if (netdev->downscript)
6115 strprint(retv, inlen, "%s", netdev->downscript);
6116
6117 return fulllen;
6118 }
6119
6120 static int get_config_net_hwaddr(const char *key, char *retv, int inlen,
6121 struct lxc_conf *c, void *data)
6122 {
6123 int len;
6124 int fulllen = 0;
6125 struct lxc_netdev *netdev = data;
6126
6127 if (!retv)
6128 inlen = 0;
6129 else
6130 memset(retv, 0, inlen);
6131
6132 if (!netdev)
6133 return -1;
6134
6135 if (netdev->hwaddr)
6136 strprint(retv, inlen, "%s", netdev->hwaddr);
6137
6138 return fulllen;
6139 }
6140
6141 static int get_config_net_mtu(const char *key, char *retv, int inlen,
6142 struct lxc_conf *c, void *data)
6143 {
6144 int len;
6145 int fulllen = 0;
6146 struct lxc_netdev *netdev = data;
6147
6148 if (!retv)
6149 inlen = 0;
6150 else
6151 memset(retv, 0, inlen);
6152
6153 if (!netdev)
6154 return -1;
6155
6156 if (netdev->mtu)
6157 strprint(retv, inlen, "%s", netdev->mtu);
6158
6159 return fulllen;
6160 }
6161
6162 static int get_config_net_vlan_id(const char *key, char *retv, int inlen,
6163 struct lxc_conf *c, void *data)
6164 {
6165 int len;
6166 int fulllen = 0;
6167 struct lxc_netdev *netdev = data;
6168
6169 if (!retv)
6170 inlen = 0;
6171 else
6172 memset(retv, 0, inlen);
6173
6174 if (!netdev)
6175 return -1;
6176
6177 if (netdev->type != LXC_NET_VLAN)
6178 return 0;
6179
6180 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
6181
6182 return fulllen;
6183 }
6184
6185 static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
6186 struct lxc_conf *c, void *data)
6187 {
6188 int len;
6189 char buf[INET_ADDRSTRLEN];
6190 int fulllen = 0;
6191 struct lxc_netdev *netdev = data;
6192
6193 if (!retv)
6194 inlen = 0;
6195 else
6196 memset(retv, 0, inlen);
6197
6198 if (!netdev)
6199 return -1;
6200
6201 if (netdev->ipv4_gateway_auto) {
6202 strprint(retv, inlen, "auto");
6203 } else if (netdev->ipv4_gateway_dev) {
6204 strprint(retv, inlen, "dev");
6205 } else if (netdev->ipv4_gateway) {
6206 inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
6207 strprint(retv, inlen, "%s", buf);
6208 }
6209
6210 return fulllen;
6211 }
6212
6213 static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
6214 struct lxc_conf *c, void *data)
6215 {
6216 int len;
6217 size_t listlen;
6218 char buf[INET_ADDRSTRLEN];
6219 struct lxc_list *it;
6220 int fulllen = 0;
6221 struct lxc_netdev *netdev = data;
6222
6223 if (!retv)
6224 inlen = 0;
6225 else
6226 memset(retv, 0, inlen);
6227
6228 if (!netdev)
6229 return -1;
6230
6231 listlen = lxc_list_len(&netdev->ipv4);
6232
6233 lxc_list_for_each(it, &netdev->ipv4) {
6234 struct lxc_inetdev *i = it->elem;
6235 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
6236 strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
6237 (listlen-- > 1) ? "\n" : "");
6238 }
6239
6240 return fulllen;
6241 }
6242
6243 static int get_config_net_veth_ipv4_route(const char *key, char *retv, int inlen,
6244 struct lxc_conf *c, void *data)
6245 {
6246 int len;
6247 size_t listlen;
6248 char buf[INET_ADDRSTRLEN];
6249 struct lxc_list *it;
6250 int fulllen = 0;
6251 struct lxc_netdev *netdev = data;
6252
6253 if (!retv)
6254 inlen = 0;
6255 else
6256 memset(retv, 0, inlen);
6257
6258 if (!netdev)
6259 return ret_set_errno(-1, EINVAL);
6260
6261 if (netdev->type != LXC_NET_VETH)
6262 return 0;
6263
6264 listlen = lxc_list_len(&netdev->priv.veth_attr.ipv4_routes);
6265
6266 lxc_list_for_each(it, &netdev->priv.veth_attr.ipv4_routes) {
6267 struct lxc_inetdev *i = it->elem;
6268 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
6269 strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
6270 (listlen-- > 1) ? "\n" : "");
6271 }
6272
6273 return fulllen;
6274 }
6275
6276 static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
6277 struct lxc_conf *c, void *data)
6278 {
6279 int len;
6280 char buf[INET6_ADDRSTRLEN];
6281 int fulllen = 0;
6282 struct lxc_netdev *netdev = data;
6283
6284 if (!retv)
6285 inlen = 0;
6286 else
6287 memset(retv, 0, inlen);
6288
6289 if (!netdev)
6290 return -1;
6291
6292 if (netdev->ipv6_gateway_auto) {
6293 strprint(retv, inlen, "auto");
6294 } else if (netdev->ipv6_gateway_dev) {
6295 strprint(retv, inlen, "dev");
6296 } else if (netdev->ipv6_gateway) {
6297 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
6298 strprint(retv, inlen, "%s", buf);
6299 }
6300
6301 return fulllen;
6302 }
6303
6304 static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
6305 struct lxc_conf *c, void *data)
6306 {
6307 int len;
6308 size_t listlen;
6309 char buf[INET6_ADDRSTRLEN];
6310 struct lxc_list *it;
6311 int fulllen = 0;
6312 struct lxc_netdev *netdev = data;
6313
6314 if (!retv)
6315 inlen = 0;
6316 else
6317 memset(retv, 0, inlen);
6318
6319 if (!netdev)
6320 return -1;
6321
6322 listlen = lxc_list_len(&netdev->ipv6);
6323
6324 lxc_list_for_each(it, &netdev->ipv6) {
6325 struct lxc_inet6dev *i = it->elem;
6326 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
6327 strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
6328 (listlen-- > 1) ? "\n" : "");
6329 }
6330
6331 return fulllen;
6332 }
6333
6334 static int get_config_net_veth_ipv6_route(const char *key, char *retv, int inlen,
6335 struct lxc_conf *c, void *data)
6336 {
6337 int len;
6338 size_t listlen;
6339 char buf[INET6_ADDRSTRLEN];
6340 struct lxc_list *it;
6341 int fulllen = 0;
6342 struct lxc_netdev *netdev = data;
6343
6344 if (!retv)
6345 inlen = 0;
6346 else
6347 memset(retv, 0, inlen);
6348
6349 if (!netdev)
6350 return ret_set_errno(-1, EINVAL);
6351
6352 if (netdev->type != LXC_NET_VETH)
6353 return 0;
6354
6355 listlen = lxc_list_len(&netdev->priv.veth_attr.ipv6_routes);
6356
6357 lxc_list_for_each(it, &netdev->priv.veth_attr.ipv6_routes) {
6358 struct lxc_inet6dev *i = it->elem;
6359 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
6360 strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
6361 (listlen-- > 1) ? "\n" : "");
6362 }
6363
6364 return fulllen;
6365 }
6366
6367 int lxc_list_config_items(char *retv, int inlen)
6368 {
6369 size_t i;
6370 int len;
6371 int fulllen = 0;
6372
6373 if (!retv)
6374 inlen = 0;
6375 else
6376 memset(retv, 0, inlen);
6377
6378 for (i = 0; i < config_jump_table_size; i++) {
6379 char *s = config_jump_table[i].name;
6380
6381 if (s[strlen(s) - 1] == '.')
6382 continue;
6383
6384 strprint(retv, inlen, "%s\n", s);
6385 }
6386
6387 return fulllen;
6388 }
6389
6390 int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
6391 int inlen)
6392 {
6393 int len;
6394 int fulllen = 0;
6395
6396 if (!retv)
6397 inlen = 0;
6398 else
6399 memset(retv, 0, inlen);
6400
6401 if (!strcmp(key, "lxc.apparmor")) {
6402 strprint(retv, inlen, "allow_incomplete\n");
6403 strprint(retv, inlen, "allow_nesting\n");
6404 strprint(retv, inlen, "profile\n");
6405 strprint(retv, inlen, "raw\n");
6406 } else if (!strcmp(key, "lxc.cgroup")) {
6407 strprint(retv, inlen, "dir\n");
6408 } else if (!strcmp(key, "lxc.selinux")) {
6409 strprint(retv, inlen, "context\n");
6410 strprint(retv, inlen, "context.keyring\n");
6411 } else if (!strcmp(key, "lxc.mount")) {
6412 strprint(retv, inlen, "auto\n");
6413 strprint(retv, inlen, "entry\n");
6414 strprint(retv, inlen, "fstab\n");
6415 } else if (!strcmp(key, "lxc.rootfs")) {
6416 strprint(retv, inlen, "mount\n");
6417 strprint(retv, inlen, "options\n");
6418 strprint(retv, inlen, "path\n");
6419 } else if (!strcmp(key, "lxc.uts")) {
6420 strprint(retv, inlen, "name\n");
6421 } else if (!strcmp(key, "lxc.hook")) {
6422 strprint(retv, inlen, "autodev\n");
6423 strprint(retv, inlen, "autodevtmpfssize\n");
6424 strprint(retv, inlen, "clone\n");
6425 strprint(retv, inlen, "destroy\n");
6426 strprint(retv, inlen, "mount\n");
6427 strprint(retv, inlen, "post-stop\n");
6428 strprint(retv, inlen, "pre-mount\n");
6429 strprint(retv, inlen, "pre-start\n");
6430 strprint(retv, inlen, "start-host\n");
6431 strprint(retv, inlen, "start\n");
6432 strprint(retv, inlen, "stop\n");
6433 } else if (!strcmp(key, "lxc.cap")) {
6434 strprint(retv, inlen, "drop\n");
6435 strprint(retv, inlen, "keep\n");
6436 } else if (!strcmp(key, "lxc.console")) {
6437 strprint(retv, inlen, "logfile\n");
6438 strprint(retv, inlen, "path\n");
6439 } else if (!strcmp(key, "lxc.seccomp")) {
6440 strprint(retv, inlen, "profile\n");
6441 } else if (!strcmp(key, "lxc.signal")) {
6442 strprint(retv, inlen, "halt\n");
6443 strprint(retv, inlen, "reboot\n");
6444 strprint(retv, inlen, "stop\n");
6445 } else if (!strcmp(key, "lxc.start")) {
6446 strprint(retv, inlen, "auto\n");
6447 strprint(retv, inlen, "delay\n");
6448 strprint(retv, inlen, "order\n");
6449 } else if (!strcmp(key, "lxc.monitor")) {
6450 strprint(retv, inlen, "unshare\n");
6451 } else if (!strcmp(key, "lxc.keyring")) {
6452 strprint(retv, inlen, "session\n");
6453 } else {
6454 fulllen = -1;
6455 }
6456
6457 return fulllen;
6458 }
6459
6460 int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
6461 {
6462 int len;
6463 const char *idxstring;
6464 struct lxc_netdev *netdev;
6465 int fulllen = 0;
6466 ssize_t idx = -1;
6467
6468 idxstring = key + 8;
6469 if (!isdigit(*idxstring))
6470 return -1;
6471
6472 (void)get_network_config_ops(key, c, &idx, NULL);
6473 if (idx < 0)
6474 return -1;
6475
6476 netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
6477 if (!netdev)
6478 return -1;
6479
6480 if (!retv)
6481 inlen = 0;
6482 else
6483 memset(retv, 0, inlen);
6484
6485 strprint(retv, inlen, "type\n");
6486 strprint(retv, inlen, "script.up\n");
6487 strprint(retv, inlen, "script.down\n");
6488
6489 if (netdev->type != LXC_NET_EMPTY) {
6490 strprint(retv, inlen, "flags\n");
6491 strprint(retv, inlen, "link\n");
6492 strprint(retv, inlen, "name\n");
6493 strprint(retv, inlen, "hwaddr\n");
6494 strprint(retv, inlen, "mtu\n");
6495 strprint(retv, inlen, "ipv6.address\n");
6496 strprint(retv, inlen, "ipv6.gateway\n");
6497 strprint(retv, inlen, "ipv4.address\n");
6498 strprint(retv, inlen, "ipv4.gateway\n");
6499 }
6500
6501 switch (netdev->type) {
6502 case LXC_NET_VETH:
6503 strprint(retv, inlen, "veth.pair\n");
6504 strprint(retv, inlen, "veth.ipv4.route\n");
6505 strprint(retv, inlen, "veth.ipv6.route\n");
6506 strprint(retv, inlen, "veth.vlan.id\n");
6507 break;
6508 case LXC_NET_MACVLAN:
6509 strprint(retv, inlen, "macvlan.mode\n");
6510 break;
6511 case LXC_NET_IPVLAN:
6512 strprint(retv, inlen, "ipvlan.mode\n");
6513 strprint(retv, inlen, "ipvlan.isolation\n");
6514 break;
6515 case LXC_NET_VLAN:
6516 strprint(retv, inlen, "vlan.id\n");
6517 break;
6518 case LXC_NET_PHYS:
6519 break;
6520 }
6521
6522 return fulllen;
6523 }