]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nspawn/nspawn-settings.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / nspawn / nspawn-settings.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f757855e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2015 Lennart Poettering
f757855e
LP
6***/
7
b5efdb8a 8#include "alloc-util.h"
f757855e 9#include "cap-list.h"
7b3e062c 10#include "conf-parser.h"
f6d6bad1 11#include "nspawn-network.h"
f757855e 12#include "nspawn-settings.h"
7732f92b 13#include "parse-util.h"
7b3e062c 14#include "process-util.h"
22b28dfd
LP
15#include "socket-util.h"
16#include "string-util.h"
7b3e062c 17#include "strv.h"
0de7acce 18#include "user-util.h"
7b3e062c 19#include "util.h"
f757855e
LP
20
21int settings_load(FILE *f, const char *path, Settings **ret) {
22 _cleanup_(settings_freep) Settings *s = NULL;
23 int r;
24
25 assert(path);
26 assert(ret);
27
28 s = new0(Settings, 1);
29 if (!s)
30 return -ENOMEM;
31
7732f92b 32 s->start_mode = _START_MODE_INVALID;
f757855e 33 s->personality = PERSONALITY_INVALID;
0de7acce
LP
34 s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
35 s->uid_shift = UID_INVALID;
36 s->uid_range = UID_INVALID;
f757855e
LP
37
38 s->read_only = -1;
39 s->volatile_mode = _VOLATILE_MODE_INVALID;
0de7acce 40 s->userns_chown = -1;
f757855e
LP
41
42 s->private_network = -1;
43 s->network_veth = -1;
44
45 r = config_parse(NULL, path, f,
46 "Exec\0"
47 "Network\0"
48 "Files\0",
49 config_item_perf_lookup, nspawn_gperf_lookup,
bcde742e 50 CONFIG_PARSE_WARN,
f757855e
LP
51 s);
52 if (r < 0)
53 return r;
54
0de7acce
LP
55 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
56 * both fields shall be initialized or neither. */
57 if (s->userns_mode == USER_NAMESPACE_PICK)
58 s->userns_chown = true;
59 else if (s->userns_mode != _USER_NAMESPACE_MODE_INVALID && s->userns_chown < 0)
60 s->userns_chown = false;
61
62 if (s->userns_chown >= 0 && s->userns_mode == _USER_NAMESPACE_MODE_INVALID)
63 s->userns_mode = USER_NAMESPACE_NO;
64
1cc6c93a 65 *ret = TAKE_PTR(s);
f757855e
LP
66
67 return 0;
68}
69
70Settings* settings_free(Settings *s) {
71
72 if (!s)
73 return NULL;
74
75 strv_free(s->parameters);
76 strv_free(s->environment);
77 free(s->user);
b53ede69
PW
78 free(s->pivot_root_new);
79 free(s->pivot_root_old);
5f932eb9 80 free(s->working_directory);
960e4569
LP
81 strv_free(s->syscall_whitelist);
82 strv_free(s->syscall_blacklist);
f757855e
LP
83
84 strv_free(s->network_interfaces);
85 strv_free(s->network_macvlan);
86 strv_free(s->network_ipvlan);
f6d6bad1 87 strv_free(s->network_veth_extra);
f757855e 88 free(s->network_bridge);
22b28dfd 89 free(s->network_zone);
f757855e
LP
90 expose_port_free_all(s->expose_ports);
91
92 custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
6b430fdb 93 return mfree(s);
f757855e
LP
94}
95
0e265674
LP
96bool settings_private_network(Settings *s) {
97 assert(s);
98
99 return
100 s->private_network > 0 ||
101 s->network_veth > 0 ||
102 s->network_bridge ||
22b28dfd 103 s->network_zone ||
0e265674
LP
104 s->network_interfaces ||
105 s->network_macvlan ||
f6d6bad1
LP
106 s->network_ipvlan ||
107 s->network_veth_extra;
0e265674
LP
108}
109
110bool settings_network_veth(Settings *s) {
111 assert(s);
112
113 return
114 s->network_veth > 0 ||
22b28dfd
LP
115 s->network_bridge ||
116 s->network_zone;
0e265674
LP
117}
118
f757855e
LP
119DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
120
121int config_parse_expose_port(
122 const char *unit,
123 const char *filename,
124 unsigned line,
125 const char *section,
126 unsigned section_line,
127 const char *lvalue,
128 int ltype,
129 const char *rvalue,
130 void *data,
131 void *userdata) {
132
133 Settings *s = data;
134 int r;
135
136 assert(filename);
137 assert(lvalue);
138 assert(rvalue);
139
140 r = expose_port_parse(&s->expose_ports, rvalue);
141 if (r == -EEXIST) {
142 log_syntax(unit, LOG_ERR, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
143 return 0;
144 }
145 if (r < 0) {
146 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse host port %s: %m", rvalue);
147 return 0;
148 }
149
150 return 0;
151}
152
153int config_parse_capability(
154 const char *unit,
155 const char *filename,
156 unsigned line,
157 const char *section,
158 unsigned section_line,
159 const char *lvalue,
160 int ltype,
161 const char *rvalue,
162 void *data,
163 void *userdata) {
164
165 uint64_t u = 0, *result = data;
166 int r;
167
168 assert(filename);
169 assert(lvalue);
170 assert(rvalue);
171
172 for (;;) {
173 _cleanup_free_ char *word = NULL;
174 int cap;
175
176 r = extract_first_word(&rvalue, &word, NULL, 0);
177 if (r < 0) {
178 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue);
179 return 0;
180 }
181 if (r == 0)
182 break;
183
184 cap = capability_from_name(word);
185 if (cap < 0) {
12ca818f 186 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability, ignoring: %s", word);
f757855e
LP
187 continue;
188 }
189
1898e5f9 190 u |= UINT64_C(1) << cap;
f757855e
LP
191 }
192
193 if (u == 0)
194 return 0;
195
196 *result |= u;
197 return 0;
198}
199
200int config_parse_id128(
201 const char *unit,
202 const char *filename,
203 unsigned line,
204 const char *section,
205 unsigned section_line,
206 const char *lvalue,
207 int ltype,
208 const char *rvalue,
209 void *data,
210 void *userdata) {
211
212 sd_id128_t t, *result = data;
213 int r;
214
215 assert(filename);
216 assert(lvalue);
217 assert(rvalue);
218
219 r = sd_id128_from_string(rvalue, &t);
220 if (r < 0) {
221 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
222 return 0;
223 }
224
225 *result = t;
226 return 0;
227}
228
b53ede69
PW
229int config_parse_pivot_root(
230 const char *unit,
231 const char *filename,
232 unsigned line,
233 const char *section,
234 unsigned section_line,
235 const char *lvalue,
236 int ltype,
237 const char *rvalue,
238 void *data,
239 void *userdata) {
240
241 Settings *settings = data;
242 int r;
243
244 assert(filename);
245 assert(lvalue);
246 assert(rvalue);
247
248 r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue);
249 if (r < 0) {
250 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
251 return 0;
252 }
253
254 return 0;
255}
256
f757855e
LP
257int config_parse_bind(
258 const char *unit,
259 const char *filename,
260 unsigned line,
261 const char *section,
262 unsigned section_line,
263 const char *lvalue,
264 int ltype,
265 const char *rvalue,
266 void *data,
267 void *userdata) {
268
269 Settings *settings = data;
270 int r;
271
272 assert(filename);
273 assert(lvalue);
274 assert(rvalue);
275
276 r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
277 if (r < 0) {
278 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
279 return 0;
280 }
281
282 return 0;
283}
284
285int config_parse_tmpfs(
286 const char *unit,
287 const char *filename,
288 unsigned line,
289 const char *section,
290 unsigned section_line,
291 const char *lvalue,
292 int ltype,
293 const char *rvalue,
294 void *data,
295 void *userdata) {
296
297 Settings *settings = data;
298 int r;
299
300 assert(filename);
301 assert(lvalue);
302 assert(rvalue);
303
304 r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
305 if (r < 0) {
306 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
307 return 0;
308 }
309
f6d6bad1
LP
310 return 0;
311}
f757855e 312
7b4318b6
LP
313int config_parse_overlay(
314 const char *unit,
315 const char *filename,
316 unsigned line,
317 const char *section,
318 unsigned section_line,
319 const char *lvalue,
320 int ltype,
321 const char *rvalue,
322 void *data,
323 void *userdata) {
324
325 Settings *settings = data;
326 int r;
327
328 assert(filename);
329 assert(lvalue);
330 assert(rvalue);
331
332 r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
333 if (r < 0)
334 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid overlay file system specification %s, ignoring: %m", rvalue);
335
336 return 0;
337}
338
f6d6bad1
LP
339int config_parse_veth_extra(
340 const char *unit,
341 const char *filename,
342 unsigned line,
343 const char *section,
344 unsigned section_line,
345 const char *lvalue,
346 int ltype,
347 const char *rvalue,
348 void *data,
349 void *userdata) {
350
351 Settings *settings = data;
352 int r;
353
354 assert(filename);
355 assert(lvalue);
356 assert(rvalue);
357
358 r = veth_extra_parse(&settings->network_veth_extra, rvalue);
359 if (r < 0) {
360 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
361 return 0;
362 }
f757855e
LP
363
364 return 0;
365}
7732f92b 366
22b28dfd
LP
367int config_parse_network_zone(
368 const char *unit,
369 const char *filename,
370 unsigned line,
371 const char *section,
372 unsigned section_line,
373 const char *lvalue,
374 int ltype,
375 const char *rvalue,
376 void *data,
377 void *userdata) {
378
379 Settings *settings = data;
380 _cleanup_free_ char *j = NULL;
381
382 assert(filename);
383 assert(lvalue);
384 assert(rvalue);
385
386 j = strappend("vz-", rvalue);
387 if (!ifname_valid(j)) {
388 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name %s, ignoring: %m", rvalue);
389 return 0;
390 }
391
f9ecfd3b 392 free_and_replace(settings->network_zone, j);
22b28dfd
LP
393
394 return 0;
395}
396
7732f92b
LP
397int config_parse_boot(
398 const char *unit,
399 const char *filename,
400 unsigned line,
401 const char *section,
402 unsigned section_line,
403 const char *lvalue,
404 int ltype,
405 const char *rvalue,
406 void *data,
407 void *userdata) {
408
409 Settings *settings = data;
410 int r;
411
412 assert(filename);
413 assert(lvalue);
414 assert(rvalue);
415
416 r = parse_boolean(rvalue);
417 if (r < 0) {
418 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue);
419 return 0;
420 }
421
422 if (r > 0) {
423 if (settings->start_mode == START_PID2)
424 goto conflict;
425
426 settings->start_mode = START_BOOT;
427 } else {
428 if (settings->start_mode == START_BOOT)
429 goto conflict;
430
431 if (settings->start_mode < 0)
432 settings->start_mode = START_PID1;
433 }
434
435 return 0;
436
437conflict:
438 log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
439 return 0;
440}
441
442int config_parse_pid2(
443 const char *unit,
444 const char *filename,
445 unsigned line,
446 const char *section,
447 unsigned section_line,
448 const char *lvalue,
449 int ltype,
450 const char *rvalue,
451 void *data,
452 void *userdata) {
453
454 Settings *settings = data;
455 int r;
456
457 assert(filename);
458 assert(lvalue);
459 assert(rvalue);
460
461 r = parse_boolean(rvalue);
462 if (r < 0) {
463 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue);
464 return 0;
465 }
466
467 if (r > 0) {
468 if (settings->start_mode == START_BOOT)
469 goto conflict;
470
471 settings->start_mode = START_PID2;
472 } else {
473 if (settings->start_mode == START_PID2)
474 goto conflict;
475
476 if (settings->start_mode < 0)
477 settings->start_mode = START_PID1;
478 }
479
480 return 0;
481
482conflict:
483 log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
484 return 0;
485}
0de7acce
LP
486
487int config_parse_private_users(
488 const char *unit,
489 const char *filename,
490 unsigned line,
491 const char *section,
492 unsigned section_line,
493 const char *lvalue,
494 int ltype,
495 const char *rvalue,
496 void *data,
497 void *userdata) {
498
499 Settings *settings = data;
500 int r;
501
502 assert(filename);
503 assert(lvalue);
504 assert(rvalue);
505
506 r = parse_boolean(rvalue);
507 if (r == 0) {
508 /* no: User namespacing off */
509 settings->userns_mode = USER_NAMESPACE_NO;
510 settings->uid_shift = UID_INVALID;
511 settings->uid_range = UINT32_C(0x10000);
512 } else if (r > 0) {
513 /* yes: User namespacing on, UID range is read from root dir */
514 settings->userns_mode = USER_NAMESPACE_FIXED;
515 settings->uid_shift = UID_INVALID;
516 settings->uid_range = UINT32_C(0x10000);
517 } else if (streq(rvalue, "pick")) {
518 /* pick: User namespacing on, UID range is picked randomly */
519 settings->userns_mode = USER_NAMESPACE_PICK;
520 settings->uid_shift = UID_INVALID;
521 settings->uid_range = UINT32_C(0x10000);
522 } else {
523 const char *range, *shift;
524 uid_t sh, rn;
525
526 /* anything else: User namespacing on, UID range is explicitly configured */
527
528 range = strchr(rvalue, ':');
529 if (range) {
530 shift = strndupa(rvalue, range - rvalue);
531 range++;
532
533 r = safe_atou32(range, &rn);
534 if (r < 0 || rn <= 0) {
535 log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
536 return 0;
537 }
538 } else {
539 shift = rvalue;
540 rn = UINT32_C(0x10000);
541 }
542
543 r = parse_uid(shift, &sh);
544 if (r < 0) {
545 log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
546 return 0;
547 }
548
549 settings->userns_mode = USER_NAMESPACE_FIXED;
550 settings->uid_shift = sh;
551 settings->uid_range = rn;
552 }
553
554 return 0;
555}
960e4569
LP
556
557int config_parse_syscall_filter(
558 const char *unit,
559 const char *filename,
560 unsigned line,
561 const char *section,
562 unsigned section_line,
563 const char *lvalue,
564 int ltype,
565 const char *rvalue,
566 void *data,
567 void *userdata) {
568
569 Settings *settings = data;
570 bool negative;
571 const char *items;
572 int r;
573
574 assert(filename);
575 assert(lvalue);
576 assert(rvalue);
577
578 negative = rvalue[0] == '~';
579 items = negative ? rvalue + 1 : rvalue;
580
581 for (;;) {
582 _cleanup_free_ char *word = NULL;
583
584 r = extract_first_word(&items, &word, NULL, 0);
585 if (r == 0)
586 break;
587 if (r == -ENOMEM)
588 return log_oom();
589 if (r < 0) {
590 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
591 return 0;
592 }
593
594 if (negative)
595 r = strv_extend(&settings->syscall_blacklist, word);
596 else
597 r = strv_extend(&settings->syscall_whitelist, word);
598 if (r < 0)
599 return log_oom();
600 }
601
602 return 0;
603}