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