1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include "alloc-util.h"
23 #include "conf-parser.h"
24 #include "nspawn-network.h"
25 #include "nspawn-settings.h"
26 #include "parse-util.h"
27 #include "process-util.h"
28 #include "socket-util.h"
29 #include "string-util.h"
31 #include "user-util.h"
34 int settings_load(FILE *f
, const char *path
, Settings
**ret
) {
35 _cleanup_(settings_freep
) Settings
*s
= NULL
;
41 s
= new0(Settings
, 1);
45 s
->start_mode
= _START_MODE_INVALID
;
46 s
->personality
= PERSONALITY_INVALID
;
47 s
->userns_mode
= _USER_NAMESPACE_MODE_INVALID
;
48 s
->uid_shift
= UID_INVALID
;
49 s
->uid_range
= UID_INVALID
;
52 s
->volatile_mode
= _VOLATILE_MODE_INVALID
;
55 s
->private_network
= -1;
58 r
= config_parse(NULL
, path
, f
,
62 config_item_perf_lookup
, nspawn_gperf_lookup
,
68 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
69 * both fields shall be initialized or neither. */
70 if (s
->userns_mode
== USER_NAMESPACE_PICK
)
71 s
->userns_chown
= true;
72 else if (s
->userns_mode
!= _USER_NAMESPACE_MODE_INVALID
&& s
->userns_chown
< 0)
73 s
->userns_chown
= false;
75 if (s
->userns_chown
>= 0 && s
->userns_mode
== _USER_NAMESPACE_MODE_INVALID
)
76 s
->userns_mode
= USER_NAMESPACE_NO
;
84 Settings
* settings_free(Settings
*s
) {
89 strv_free(s
->parameters
);
90 strv_free(s
->environment
);
92 free(s
->pivot_root_new
);
93 free(s
->pivot_root_old
);
94 free(s
->working_directory
);
95 strv_free(s
->syscall_whitelist
);
96 strv_free(s
->syscall_blacklist
);
98 strv_free(s
->network_interfaces
);
99 strv_free(s
->network_macvlan
);
100 strv_free(s
->network_ipvlan
);
101 strv_free(s
->network_veth_extra
);
102 free(s
->network_bridge
);
103 free(s
->network_zone
);
104 expose_port_free_all(s
->expose_ports
);
106 custom_mount_free_all(s
->custom_mounts
, s
->n_custom_mounts
);
110 bool settings_private_network(Settings
*s
) {
114 s
->private_network
> 0 ||
115 s
->network_veth
> 0 ||
118 s
->network_interfaces
||
119 s
->network_macvlan
||
121 s
->network_veth_extra
;
124 bool settings_network_veth(Settings
*s
) {
128 s
->network_veth
> 0 ||
133 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode
, volatile_mode
, VolatileMode
, "Failed to parse volatile mode");
135 int config_parse_expose_port(
137 const char *filename
,
140 unsigned section_line
,
154 r
= expose_port_parse(&s
->expose_ports
, rvalue
);
156 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Duplicate port specification, ignoring: %s", rvalue
);
160 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse host port %s: %m", rvalue
);
167 int config_parse_capability(
169 const char *filename
,
172 unsigned section_line
,
179 uint64_t u
= 0, *result
= data
;
187 _cleanup_free_
char *word
= NULL
;
190 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
192 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract capability string, ignoring: %s", rvalue
);
198 cap
= capability_from_name(word
);
200 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability, ignoring: %s", word
);
204 u
|= UINT64_C(1) << cap
;
214 int config_parse_id128(
216 const char *filename
,
219 unsigned section_line
,
226 sd_id128_t t
, *result
= data
;
233 r
= sd_id128_from_string(rvalue
, &t
);
235 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
243 int config_parse_pivot_root(
245 const char *filename
,
248 unsigned section_line
,
255 Settings
*settings
= data
;
262 r
= pivot_root_parse(&settings
->pivot_root_new
, &settings
->pivot_root_old
, rvalue
);
264 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid pivot root mount specification %s: %m", rvalue
);
271 int config_parse_bind(
273 const char *filename
,
276 unsigned section_line
,
283 Settings
*settings
= data
;
290 r
= bind_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
292 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid bind mount specification %s: %m", rvalue
);
299 int config_parse_tmpfs(
301 const char *filename
,
304 unsigned section_line
,
311 Settings
*settings
= data
;
318 r
= tmpfs_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
);
320 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid temporary file system specification %s: %m", rvalue
);
327 int config_parse_overlay(
329 const char *filename
,
332 unsigned section_line
,
339 Settings
*settings
= data
;
346 r
= overlay_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
348 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid overlay file system specification %s, ignoring: %m", rvalue
);
353 int config_parse_veth_extra(
355 const char *filename
,
358 unsigned section_line
,
365 Settings
*settings
= data
;
372 r
= veth_extra_parse(&settings
->network_veth_extra
, rvalue
);
374 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid extra virtual Ethernet link specification %s: %m", rvalue
);
381 int config_parse_network_zone(
383 const char *filename
,
386 unsigned section_line
,
393 Settings
*settings
= data
;
394 _cleanup_free_
char *j
= NULL
;
400 j
= strappend("vz-", rvalue
);
401 if (!ifname_valid(j
)) {
402 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid network zone name %s, ignoring: %m", rvalue
);
406 free_and_replace(settings
->network_zone
, j
);
411 int config_parse_boot(
413 const char *filename
,
416 unsigned section_line
,
423 Settings
*settings
= data
;
430 r
= parse_boolean(rvalue
);
432 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue
);
437 if (settings
->start_mode
== START_PID2
)
440 settings
->start_mode
= START_BOOT
;
442 if (settings
->start_mode
== START_BOOT
)
445 if (settings
->start_mode
< 0)
446 settings
->start_mode
= START_PID1
;
452 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
456 int config_parse_pid2(
458 const char *filename
,
461 unsigned section_line
,
468 Settings
*settings
= data
;
475 r
= parse_boolean(rvalue
);
477 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue
);
482 if (settings
->start_mode
== START_BOOT
)
485 settings
->start_mode
= START_PID2
;
487 if (settings
->start_mode
== START_PID2
)
490 if (settings
->start_mode
< 0)
491 settings
->start_mode
= START_PID1
;
497 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
501 int config_parse_private_users(
503 const char *filename
,
506 unsigned section_line
,
513 Settings
*settings
= data
;
520 r
= parse_boolean(rvalue
);
522 /* no: User namespacing off */
523 settings
->userns_mode
= USER_NAMESPACE_NO
;
524 settings
->uid_shift
= UID_INVALID
;
525 settings
->uid_range
= UINT32_C(0x10000);
527 /* yes: User namespacing on, UID range is read from root dir */
528 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
529 settings
->uid_shift
= UID_INVALID
;
530 settings
->uid_range
= UINT32_C(0x10000);
531 } else if (streq(rvalue
, "pick")) {
532 /* pick: User namespacing on, UID range is picked randomly */
533 settings
->userns_mode
= USER_NAMESPACE_PICK
;
534 settings
->uid_shift
= UID_INVALID
;
535 settings
->uid_range
= UINT32_C(0x10000);
537 const char *range
, *shift
;
540 /* anything else: User namespacing on, UID range is explicitly configured */
542 range
= strchr(rvalue
, ':');
544 shift
= strndupa(rvalue
, range
- rvalue
);
547 r
= safe_atou32(range
, &rn
);
548 if (r
< 0 || rn
<= 0) {
549 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID range invalid, ignoring: %s", range
);
554 rn
= UINT32_C(0x10000);
557 r
= parse_uid(shift
, &sh
);
559 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID shift invalid, ignoring: %s", range
);
563 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
564 settings
->uid_shift
= sh
;
565 settings
->uid_range
= rn
;
571 int config_parse_syscall_filter(
573 const char *filename
,
576 unsigned section_line
,
583 Settings
*settings
= data
;
592 negative
= rvalue
[0] == '~';
593 items
= negative
? rvalue
+ 1 : rvalue
;
596 _cleanup_free_
char *word
= NULL
;
598 r
= extract_first_word(&items
, &word
, NULL
, 0);
604 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue
);
609 r
= strv_extend(&settings
->syscall_blacklist
, word
);
611 r
= strv_extend(&settings
->syscall_whitelist
, word
);