]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/firstboot/firstboot.c
4c24d38716d97e7ffe7957eee86ed52ab83522e1
[thirdparty/systemd.git] / src / firstboot / firstboot.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4 #include <getopt.h>
5 #include <unistd.h>
6
7 #include "sd-bus.h"
8 #include "sd-id128.h"
9 #include "sd-varlink.h"
10
11 #include "alloc-util.h"
12 #include "ask-password-api.h"
13 #include "build.h"
14 #include "bus-error.h"
15 #include "bus-locator.h"
16 #include "bus-unit-util.h"
17 #include "bus-util.h"
18 #include "bus-wait-for-jobs.h"
19 #include "chase.h"
20 #include "copy.h"
21 #include "creds-util.h"
22 #include "dissect-image.h"
23 #include "env-file.h"
24 #include "errno-util.h"
25 #include "fd-util.h"
26 #include "fileio.h"
27 #include "fs-util.h"
28 #include "glyph-util.h"
29 #include "hostname-util.h"
30 #include "image-policy.h"
31 #include "kbd-util.h"
32 #include "label.h"
33 #include "label-util.h"
34 #include "libcrypt-util.h"
35 #include "locale-setup.h"
36 #include "locale-util.h"
37 #include "lock-util.h"
38 #include "loop-util.h"
39 #include "main-func.h"
40 #include "memory-util.h"
41 #include "mount-util.h"
42 #include "os-util.h"
43 #include "parse-argument.h"
44 #include "parse-util.h"
45 #include "password-quality-util.h"
46 #include "path-util.h"
47 #include "pretty-print.h"
48 #include "proc-cmdline.h"
49 #include "prompt-util.h"
50 #include "runtime-scope.h"
51 #include "smack-util.h"
52 #include "stat-util.h"
53 #include "string-util.h"
54 #include "strv.h"
55 #include "terminal-util.h"
56 #include "time-util.h"
57 #include "tmpfile-util-label.h"
58 #include "user-util.h"
59 #include "vconsole-util.h"
60
61 static char *arg_root = NULL;
62 static char *arg_image = NULL;
63 static char *arg_locale = NULL; /* $LANG */
64 static char *arg_locale_messages = NULL; /* $LC_MESSAGES */
65 static char *arg_keymap = NULL;
66 static char *arg_timezone = NULL;
67 static char *arg_hostname = NULL;
68 static sd_id128_t arg_machine_id = {};
69 static char *arg_root_password = NULL;
70 static char *arg_root_shell = NULL;
71 static char *arg_kernel_cmdline = NULL;
72 static bool arg_prompt_locale = false;
73 static bool arg_prompt_keymap = false;
74 static bool arg_prompt_keymap_auto = false;
75 static bool arg_prompt_timezone = false;
76 static bool arg_prompt_hostname = false;
77 static bool arg_prompt_root_password = false;
78 static bool arg_prompt_root_shell = false;
79 static bool arg_copy_locale = false;
80 static bool arg_copy_keymap = false;
81 static bool arg_copy_timezone = false;
82 static bool arg_copy_root_password = false;
83 static bool arg_copy_root_shell = false;
84 static bool arg_force = false;
85 static bool arg_delete_root_password = false;
86 static bool arg_root_password_is_hashed = false;
87 static bool arg_welcome = true;
88 static bool arg_reset = false;
89 static ImagePolicy *arg_image_policy = NULL;
90 static bool arg_chrome = true;
91 static bool arg_mute_console = false;
92
93 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
94 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
95 STATIC_DESTRUCTOR_REGISTER(arg_locale, freep);
96 STATIC_DESTRUCTOR_REGISTER(arg_locale_messages, freep);
97 STATIC_DESTRUCTOR_REGISTER(arg_keymap, freep);
98 STATIC_DESTRUCTOR_REGISTER(arg_timezone, freep);
99 STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep);
100 STATIC_DESTRUCTOR_REGISTER(arg_root_password, erase_and_freep);
101 STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
102 STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
103 STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
104
105 static void print_welcome(int rfd, sd_varlink **mute_console_link) {
106 _cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
107 static bool done = false;
108 const char *pn, *ac;
109 int r;
110
111 assert(rfd >= 0);
112 assert(mute_console_link);
113
114 if (!*mute_console_link && arg_mute_console)
115 (void) mute_console(mute_console_link);
116
117 if (!arg_welcome)
118 return;
119
120 if (done) {
121 putchar('\n'); /* Add some breathing room between multiple prompts */
122 return;
123 }
124
125 (void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
126
127 if (arg_chrome)
128 chrome_show("Initial Setup", /* bottom= */ NULL);
129
130 r = parse_os_release_at(rfd,
131 "PRETTY_NAME", &pretty_name,
132 "NAME", &os_name,
133 "ANSI_COLOR", &ansi_color);
134 if (r < 0)
135 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
136 "Failed to read os-release file, ignoring: %m");
137
138 pn = os_release_pretty_name(pretty_name, os_name);
139 ac = isempty(ansi_color) ? "0" : ansi_color;
140
141 if (colors_enabled())
142 printf(ANSI_HIGHLIGHT "Welcome to " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
143 else
144 printf("Welcome to %s!\n", pn);
145
146 putchar('\n');
147 if (emoji_enabled()) {
148 fputs(glyph(GLYPH_SPARKLES), stdout);
149 putchar(' ');
150 }
151 printf("Please configure the system!\n\n");
152
153 done = true;
154 }
155
156 static int should_configure(int dir_fd, const char *filename) {
157 _cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
158 int r;
159
160 assert(dir_fd >= 0);
161 assert(filename);
162
163 if (streq(filename, "passwd") && !arg_force)
164 /* We may need to do additional checks, so open the file. */
165 r = xfopenat(dir_fd, filename, "re", O_NOFOLLOW, &passwd);
166 else
167 r = RET_NERRNO(faccessat(dir_fd, filename, F_OK, AT_SYMLINK_NOFOLLOW));
168
169 if (r == -ENOENT)
170 return true; /* missing */
171 if (r < 0)
172 return log_error_errno(r, "Failed to access %s: %m", filename);
173 if (arg_force)
174 return true; /* exists, but if --force was given we should still configure the file. */
175
176 if (!passwd)
177 return false;
178
179 /* In case of /etc/passwd, do an additional check for the root password field.
180 * We first check that passwd redirects to shadow, and then we check shadow.
181 */
182 struct passwd *i;
183 while ((r = fgetpwent_sane(passwd, &i)) > 0) {
184 if (!streq(i->pw_name, "root"))
185 continue;
186
187 if (streq_ptr(i->pw_passwd, PASSWORD_SEE_SHADOW))
188 break;
189 log_debug("passwd: root account with non-shadow password found, treating root as configured");
190 return false;
191 }
192 if (r < 0)
193 return log_error_errno(r, "Failed to read %s: %m", filename);
194 if (r == 0) {
195 log_debug("No root account found in %s, assuming root is not configured.", filename);
196 return true;
197 }
198
199 r = xfopenat(dir_fd, "shadow", "re", O_NOFOLLOW, &shadow);
200 if (r == -ENOENT) {
201 log_debug("No shadow file found, assuming root is not configured.");
202 return true; /* missing */
203 }
204 if (r < 0)
205 return log_error_errno(r, "Failed to access shadow: %m");
206
207 struct spwd *j;
208 while ((r = fgetspent_sane(shadow, &j)) > 0) {
209 if (!streq(j->sp_namp, "root"))
210 continue;
211
212 bool unprovisioned = streq_ptr(j->sp_pwdp, PASSWORD_UNPROVISIONED);
213 log_debug("Root account found, %s.",
214 unprovisioned ? "with unprovisioned password, treating root as not configured" :
215 "treating root as configured");
216 return unprovisioned;
217 }
218 if (r < 0)
219 return log_error_errno(r, "Failed to read shadow: %m");
220 assert(r == 0);
221 log_debug("No root account found in shadow, assuming root is not configured.");
222 return true;
223 }
224
225 static int locale_is_ok(const char *name, void *userdata) {
226 int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
227
228 r = dir_fd_is_root(rfd);
229 if (r < 0)
230 log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
231
232 return r != 0 ? locale_is_installed(name) > 0 : locale_is_valid(name);
233 }
234
235 static int prompt_locale(int rfd, sd_varlink **mute_console_link) {
236 _cleanup_strv_free_ char **locales = NULL;
237 bool acquired_from_creds = false;
238 int r;
239
240 assert(rfd >= 0);
241
242 if (arg_locale || arg_locale_messages)
243 return 0;
244
245 r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
246 if (r < 0)
247 log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
248 else
249 acquired_from_creds = true;
250
251 r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
252 if (r < 0)
253 log_debug_errno(r, "Failed to read credential firstboot.locale-messages, ignoring: %m");
254 else
255 acquired_from_creds = true;
256
257 if (acquired_from_creds) {
258 log_debug("Acquired locale from credentials.");
259 return 0;
260 }
261
262 if (!arg_prompt_locale) {
263 log_debug("Prompting for locale was not requested.");
264 return 0;
265 }
266
267 r = get_locales(&locales);
268 if (r < 0)
269 return log_error_errno(r, "Cannot query locales list: %m");
270
271 if (strv_isempty(locales))
272 log_debug("No locales found, skipping locale selection.");
273 else if (strv_length(locales) == 1) {
274
275 if (streq(locales[0], SYSTEMD_DEFAULT_LOCALE))
276 log_debug("Only installed locale is default locale anyway, not setting locale explicitly.");
277 else {
278 log_debug("Only a single locale available (%s), selecting it as default.", locales[0]);
279
280 arg_locale = strdup(locales[0]);
281 if (!arg_locale)
282 return log_oom();
283
284 /* Not setting arg_locale_message here, since it defaults to LANG anyway */
285 }
286 } else {
287 print_welcome(rfd, mute_console_link);
288
289 r = prompt_loop("Please enter the new system locale name or number",
290 GLYPH_WORLD,
291 locales,
292 /* accepted= */ NULL,
293 /* ellipsize_percentage= */ 60,
294 /* n_columns= */ 3,
295 /* column_width= */ 20,
296 locale_is_ok,
297 /* refresh= */ NULL,
298 FD_TO_PTR(rfd),
299 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
300 &arg_locale);
301 if (r < 0)
302 return r;
303 if (isempty(arg_locale))
304 return 0;
305
306 r = prompt_loop("Please enter the new system message locale name or number",
307 GLYPH_WORLD,
308 locales,
309 /* accepted= */ NULL,
310 /* ellipsize_percentage= */ 60,
311 /* n_columns= */ 3,
312 /* column_width= */ 20,
313 locale_is_ok,
314 /* refresh= */ NULL,
315 FD_TO_PTR(rfd),
316 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
317 &arg_locale_messages);
318 if (r < 0)
319 return r;
320
321 /* Suppress the messages setting if it's the same as the main locale anyway */
322 if (streq_ptr(arg_locale, arg_locale_messages))
323 arg_locale_messages = mfree(arg_locale_messages);
324 }
325
326 return 0;
327 }
328
329 static int process_locale(int rfd, sd_varlink **mute_console_link) {
330 _cleanup_close_ int pfd = -EBADF;
331 _cleanup_free_ char *f = NULL;
332 char* locales[3];
333 unsigned i = 0;
334 int r;
335
336 assert(rfd >= 0);
337
338 pfd = chase_and_open_parent_at(rfd, etc_locale_conf(),
339 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
340 &f);
341 if (pfd < 0)
342 return log_error_errno(pfd, "Failed to chase /etc/locale.conf: %m");
343
344 r = should_configure(pfd, f);
345 if (r == 0)
346 log_debug("Found /etc/locale.conf, assuming locale information has been configured.");
347 if (r <= 0)
348 return r;
349
350 r = dir_fd_is_root(rfd);
351 if (r < 0)
352 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
353
354 if (arg_copy_locale && r == 0) {
355 r = copy_file_atomic_at(AT_FDCWD, etc_locale_conf(), pfd, f, 0644, COPY_REFLINK);
356 if (r != -ENOENT) {
357 if (r < 0)
358 return log_error_errno(r, "Failed to copy host's /etc/locale.conf: %m");
359
360 log_info("Copied host's /etc/locale.conf.");
361 return 0;
362 }
363 }
364
365 r = prompt_locale(rfd, mute_console_link);
366 if (r < 0)
367 return r;
368
369 if (!isempty(arg_locale))
370 locales[i++] = strjoina("LANG=", arg_locale);
371 if (!isempty(arg_locale_messages) && !streq_ptr(arg_locale_messages, arg_locale))
372 locales[i++] = strjoina("LC_MESSAGES=", arg_locale_messages);
373
374 if (i == 0)
375 return 0;
376
377 locales[i] = NULL;
378
379 r = write_env_file(
380 pfd,
381 f,
382 /* headers= */ NULL,
383 locales,
384 WRITE_ENV_FILE_LABEL);
385 if (r < 0)
386 return log_error_errno(r, "Failed to write /etc/locale.conf: %m");
387
388 log_info("/etc/locale.conf written.");
389 return 1;
390 }
391
392 static int keymap_is_ok(const char* name, void *userdata) {
393 int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
394
395 r = dir_fd_is_root(rfd);
396 if (r < 0)
397 log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
398
399 return r != 0 ? keymap_exists(name) > 0 : keymap_is_valid(name);
400 }
401
402 static int prompt_keymap(int rfd, sd_varlink **mute_console_link) {
403 _cleanup_strv_free_ char **kmaps = NULL;
404 int r;
405
406 assert(rfd >= 0);
407
408 if (arg_keymap)
409 return 0;
410
411 r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
412 if (r < 0)
413 log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
414 else {
415 log_debug("Acquired keymap from credential.");
416 return 0;
417 }
418
419 bool b;
420 if (arg_prompt_keymap_auto) {
421 _cleanup_free_ char *ttyname = NULL;
422
423 r = getttyname_harder(STDOUT_FILENO, &ttyname);
424 if (r < 0) {
425 log_debug_errno(r, "Cannot determine TTY we are connected, ignoring: %m");
426 b = false; /* if we can't resolve this, it's probably not a VT */
427 } else {
428 b = tty_is_vc_resolve(ttyname);
429 log_debug("Detected connection to local console: %s", yes_no(b));
430 }
431 } else
432 b = arg_prompt_keymap;
433 if (!b) {
434 log_debug("Prompting for keymap was not requested.");
435 return 0;
436 }
437
438 r = get_keymaps(&kmaps);
439 if (r == -ENOENT) /* no keymaps installed */
440 return log_debug_errno(r, "No keymaps are installed.");
441 if (r < 0)
442 return log_error_errno(r, "Failed to read keymaps: %m");
443
444 print_welcome(rfd, mute_console_link);
445
446 return prompt_loop(
447 "Please enter the new keymap name or number",
448 GLYPH_KEYBOARD,
449 kmaps,
450 /* accepted= */ NULL,
451 /* ellipsize_percentage= */ 60,
452 /* n_columns= */ 3,
453 /* column_width= */ 20,
454 keymap_is_ok,
455 /* refresh= */ NULL,
456 FD_TO_PTR(rfd),
457 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
458 &arg_keymap);
459 }
460
461 static int process_keymap(int rfd, sd_varlink **mute_console_link) {
462 _cleanup_close_ int pfd = -EBADF;
463 _cleanup_free_ char *f = NULL;
464 _cleanup_strv_free_ char **keymap = NULL;
465 int r;
466
467 assert(rfd >= 0);
468
469 pfd = chase_and_open_parent_at(rfd, etc_vconsole_conf(),
470 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
471 &f);
472 if (pfd < 0)
473 return log_error_errno(pfd, "Failed to chase /etc/vconsole.conf: %m");
474
475 r = should_configure(pfd, f);
476 if (r == 0)
477 log_debug("Found /etc/vconsole.conf, assuming console has been configured.");
478 if (r <= 0)
479 return r;
480
481 r = dir_fd_is_root(rfd);
482 if (r < 0)
483 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
484
485 if (arg_copy_keymap && r == 0) {
486 r = copy_file_atomic_at(AT_FDCWD, etc_vconsole_conf(), pfd, f, 0644, COPY_REFLINK);
487 if (r != -ENOENT) {
488 if (r < 0)
489 return log_error_errno(r, "Failed to copy host's /etc/vconsole.conf: %m");
490
491 log_info("Copied host's /etc/vconsole.conf.");
492 return 0;
493 }
494 }
495
496 r = prompt_keymap(rfd, mute_console_link);
497 if (r == -ENOENT)
498 return 0; /* don't fail if no keymaps are installed */
499 if (r < 0)
500 return r;
501
502 if (isempty(arg_keymap))
503 return 0;
504
505 VCContext vc = {
506 .keymap = arg_keymap,
507 };
508 _cleanup_(x11_context_clear) X11Context xc = {};
509
510 r = vconsole_convert_to_x11(&vc, /* verify= */ NULL, &xc);
511 if (r < 0)
512 return log_error_errno(r, "Failed to convert keymap data: %m");
513
514 r = vconsole_serialize(&vc, &xc, &keymap);
515 if (r < 0)
516 return log_error_errno(r, "Failed to serialize keymap data: %m");
517
518 r = write_vconsole_conf(pfd, f, keymap);
519 if (r < 0)
520 return log_error_errno(r, "Failed to write /etc/vconsole.conf: %m");
521
522 log_info("/etc/vconsole.conf written.");
523 return 1;
524 }
525
526 static int timezone_is_ok(const char *name, void *userdata) {
527 return timezone_is_valid(name, LOG_DEBUG);
528 }
529
530 static int prompt_timezone(int rfd, sd_varlink **mute_console_link) {
531 _cleanup_strv_free_ char **zones = NULL;
532 int r;
533
534 assert(rfd >= 0);
535
536 if (arg_timezone)
537 return 0;
538
539 r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
540 if (r < 0)
541 log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
542 else {
543 log_debug("Acquired timezone from credential.");
544 return 0;
545 }
546
547 if (!arg_prompt_timezone) {
548 log_debug("Prompting for timezone was not requested.");
549 return 0;
550 }
551
552 r = get_timezones(&zones);
553 if (r < 0)
554 return log_error_errno(r, "Cannot query timezone list: %m");
555
556 print_welcome(rfd, mute_console_link);
557
558 return prompt_loop(
559 "Please enter the new timezone name or number",
560 GLYPH_CLOCK,
561 zones,
562 /* accepted= */ NULL,
563 /* ellipsize_percentage= */ 30,
564 /* n_columns= */ 3,
565 /* column_width= */ 20,
566 timezone_is_ok,
567 /* refresh= */ NULL,
568 FD_TO_PTR(rfd),
569 PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
570 &arg_timezone);
571 }
572
573 static int process_timezone(int rfd, sd_varlink **mute_console_link) {
574 _cleanup_close_ int pfd = -EBADF;
575 _cleanup_free_ char *f = NULL, *relpath = NULL;
576 const char *e;
577 int r;
578
579 assert(rfd >= 0);
580
581 pfd = chase_and_open_parent_at(rfd, etc_localtime(),
582 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
583 &f);
584 if (pfd < 0)
585 return log_error_errno(pfd, "Failed to chase /etc/localtime: %m");
586
587 r = should_configure(pfd, f);
588 if (r == 0)
589 log_debug("Found /etc/localtime, assuming timezone has been configured.");
590 if (r <= 0)
591 return r;
592
593 r = dir_fd_is_root(rfd);
594 if (r < 0)
595 return log_error_errno(r, "Failed to check if directory file descriptor is root: %m");
596
597 if (arg_copy_timezone && r == 0) {
598 _cleanup_free_ char *s = NULL;
599
600 r = readlink_malloc(etc_localtime(), &s);
601 if (r != -ENOENT) {
602 if (r < 0)
603 return log_error_errno(r, "Failed to read host's /etc/localtime: %m");
604
605 r = symlinkat_atomic_full(s, pfd, f, SYMLINK_LABEL);
606 if (r < 0)
607 return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
608
609 log_info("Copied host's /etc/localtime.");
610 return 0;
611 }
612 }
613
614 r = prompt_timezone(rfd, mute_console_link);
615 if (r < 0)
616 return r;
617
618 if (isempty(arg_timezone))
619 return 0;
620
621 e = strjoina("/usr/share/zoneinfo/", arg_timezone);
622 r = path_make_relative_parent(etc_localtime(), e, &relpath);
623 if (r < 0)
624 return r;
625
626 r = symlinkat_atomic_full(relpath, pfd, f, SYMLINK_LABEL);
627 if (r < 0)
628 return log_error_errno(r, "Failed to create /etc/localtime symlink: %m");
629
630 log_info("/etc/localtime written");
631 return 0;
632 }
633
634 static int hostname_is_ok(const char *name, void *userdata) {
635 return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
636 }
637
638 static int prompt_hostname(int rfd, sd_varlink **mute_console_link) {
639 int r;
640
641 assert(rfd >= 0);
642
643 if (arg_hostname)
644 return 0;
645
646 if (!arg_prompt_hostname) {
647 log_debug("Prompting for hostname was not requested.");
648 return 0;
649 }
650
651 print_welcome(rfd, mute_console_link);
652
653 r = prompt_loop("Please enter the new hostname",
654 GLYPH_LABEL,
655 /* menu= */ NULL,
656 /* accepted= */ NULL,
657 /* ellipsize_percentage= */ 100,
658 /* n_columns= */ 3,
659 /* column_width= */ 20,
660 hostname_is_ok,
661 /* refresh= */ NULL,
662 FD_TO_PTR(rfd),
663 PROMPT_MAY_SKIP,
664 &arg_hostname);
665 if (r < 0)
666 return r;
667
668 if (arg_hostname)
669 hostname_cleanup(arg_hostname);
670
671 return 0;
672 }
673
674 static int process_hostname(int rfd, sd_varlink **mute_console_link) {
675 _cleanup_close_ int pfd = -EBADF;
676 _cleanup_free_ char *f = NULL;
677 int r;
678
679 assert(rfd >= 0);
680
681 pfd = chase_and_open_parent_at(rfd, etc_hostname(),
682 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN,
683 &f);
684 if (pfd < 0)
685 return log_error_errno(pfd, "Failed to chase /etc/hostname: %m");
686
687 r = should_configure(pfd, f);
688 if (r == 0)
689 log_debug("Found /etc/hostname, assuming hostname has been configured.");
690 if (r <= 0)
691 return r;
692
693 r = prompt_hostname(rfd, mute_console_link);
694 if (r < 0)
695 return r;
696
697 if (isempty(arg_hostname))
698 return 0;
699
700 r = write_string_file_at(pfd, f, arg_hostname,
701 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
702 if (r < 0)
703 return log_error_errno(r, "Failed to write /etc/hostname: %m");
704
705 log_info("/etc/hostname written.");
706 return 0;
707 }
708
709 static int process_machine_id(int rfd) {
710 _cleanup_close_ int pfd = -EBADF;
711 _cleanup_free_ char *f = NULL;
712 int r;
713
714 assert(rfd >= 0);
715
716 pfd = chase_and_open_parent_at(rfd, "/etc/machine-id",
717 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
718 &f);
719 if (pfd < 0)
720 return log_error_errno(pfd, "Failed to chase /etc/machine-id: %m");
721
722 r = should_configure(pfd, f);
723 if (r == 0)
724 log_debug("Found /etc/machine-id, assuming machine-id has been configured.");
725 if (r <= 0)
726 return r;
727
728 if (sd_id128_is_null(arg_machine_id)) {
729 log_debug("Initialization of machine-id was not requested, skipping.");
730 return 0;
731 }
732
733 r = write_string_file_at(pfd, "machine-id", SD_ID128_TO_STRING(arg_machine_id),
734 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
735 if (r < 0)
736 return log_error_errno(r, "Failed to write /etc/machine-id: %m");
737
738 log_info("/etc/machine-id written.");
739 return 0;
740 }
741
742 static int prompt_root_password(int rfd, sd_varlink **mute_console_link) {
743 const char *msg1, *msg2;
744 int r;
745
746 assert(rfd >= 0);
747
748 if (arg_root_password)
749 return 0;
750
751 if (get_credential_user_password("root", &arg_root_password, &arg_root_password_is_hashed) >= 0)
752 return 0;
753
754 if (!arg_prompt_root_password) {
755 log_debug("Prompting for root password was not requested.");
756 return 0;
757 }
758
759 print_welcome(rfd, mute_console_link);
760
761 msg1 = "Please enter the new root password (empty to skip):";
762 msg2 = "Please enter the new root password again:";
763
764 suggest_passwords();
765
766 for (;;) {
767 _cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
768 _cleanup_free_ char *error = NULL;
769
770 AskPasswordRequest req = {
771 .tty_fd = -EBADF,
772 .message = msg1,
773 .until = USEC_INFINITY,
774 .hup_fd = -EBADF,
775 };
776
777 r = ask_password_tty(&req, /* flags= */ 0, &a);
778 if (r < 0)
779 return log_error_errno(r, "Failed to query root password: %m");
780 if (strv_length(a) != 1)
781 return log_error_errno(SYNTHETIC_ERRNO(EIO),
782 "Received multiple passwords, where we expected one.");
783
784 if (isempty(*a)) {
785 log_info("No password entered, skipping.");
786 break;
787 }
788
789 r = check_password_quality(*a, /* old = */ NULL, "root", &error);
790 if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
791 log_warning("Password quality check is not supported, proceeding anyway.");
792 else if (r < 0)
793 return log_error_errno(r, "Failed to check password quality: %m");
794 else if (r == 0)
795 log_warning("Password is weak, accepting anyway: %s", error);
796
797 req.message = msg2;
798
799 r = ask_password_tty(&req, /* flags= */ 0, &b);
800 if (r < 0)
801 return log_error_errno(r, "Failed to query root password: %m");
802 if (strv_length(b) != 1)
803 return log_error_errno(SYNTHETIC_ERRNO(EIO),
804 "Received multiple passwords, where we expected one.");
805
806 if (!streq(*a, *b)) {
807 log_error("Entered passwords did not match, please try again.");
808 continue;
809 }
810
811 arg_root_password = TAKE_PTR(*a);
812 break;
813 }
814
815 return 0;
816 }
817
818 static int find_shell(int rfd, const char *path) {
819 int r;
820
821 assert(path);
822
823 if (!valid_shell(path))
824 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a valid shell", path);
825
826 r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL);
827 if (r < 0)
828 return log_error_errno(r, "Failed to resolve shell %s: %m", path);
829
830 return 0;
831 }
832
833 static int shell_is_ok(const char *path, void *userdata) {
834 int rfd = ASSERT_FD(PTR_TO_FD(userdata));
835
836 return find_shell(rfd, path) >= 0;
837 }
838
839 static int prompt_root_shell(int rfd, sd_varlink **mute_console_link) {
840 int r;
841
842 assert(rfd >= 0);
843
844 if (arg_root_shell)
845 return 0;
846
847 r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
848 if (r < 0)
849 log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
850 else {
851 log_debug("Acquired root shell from credential.");
852 return 0;
853 }
854
855 if (!arg_prompt_root_shell) {
856 log_debug("Prompting for root shell was not requested.");
857 return 0;
858 }
859
860 print_welcome(rfd, mute_console_link);
861
862 return prompt_loop(
863 "Please enter the new root shell",
864 GLYPH_SHELL,
865 /* menu= */ NULL,
866 /* accepted= */ NULL,
867 /* ellipsize_percentage= */ 0,
868 /* n_columns= */ 3,
869 /* column_width= */ 20,
870 shell_is_ok,
871 /* refresh= */ NULL,
872 FD_TO_PTR(rfd),
873 PROMPT_MAY_SKIP,
874 &arg_root_shell);
875 }
876
877 static int write_root_passwd(int rfd, int etc_fd, const char *password, const char *shell) {
878 _cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
879 _cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
880 int r;
881 bool found = false;
882
883 r = fopen_temporary_at_label(etc_fd, "passwd", "passwd", &passwd, &passwd_tmp);
884 if (r < 0)
885 return r;
886
887 r = xfopenat(etc_fd, "passwd", "re", O_NOFOLLOW, &original);
888 if (r < 0 && r != -ENOENT)
889 return r;
890
891 if (original) {
892 struct passwd *i;
893
894 r = copy_rights(fileno(original), fileno(passwd));
895 if (r < 0)
896 return r;
897
898 while ((r = fgetpwent_sane(original, &i)) > 0) {
899
900 if (streq(i->pw_name, "root")) {
901 if (password)
902 i->pw_passwd = (char *) password;
903 if (shell)
904 i->pw_shell = (char *) shell;
905 found = true;
906 }
907
908 r = putpwent_sane(i, passwd);
909 if (r < 0)
910 return r;
911 }
912 if (r < 0)
913 return r;
914
915 } else {
916 r = fchmod(fileno(passwd), 0644);
917 if (r < 0)
918 return -errno;
919 }
920
921 if (!found) {
922 struct passwd root = {
923 .pw_name = (char *) "root",
924 .pw_passwd = (char *) (password ?: PASSWORD_SEE_SHADOW),
925 .pw_uid = 0,
926 .pw_gid = 0,
927 .pw_gecos = (char *) "Super User",
928 .pw_dir = (char *) "/root",
929 .pw_shell = (char *) (shell ?: default_root_shell_at(rfd)),
930 };
931
932 if (errno != ENOENT)
933 return -errno;
934
935 r = putpwent_sane(&root, passwd);
936 if (r < 0)
937 return r;
938 }
939
940 r = fflush_sync_and_check(passwd);
941 if (r < 0)
942 return r;
943
944 r = renameat_and_apply_smack_floor_label(etc_fd, passwd_tmp, etc_fd, "passwd");
945 if (r < 0)
946 return r;
947
948 return 0;
949 }
950
951 static int write_root_shadow(int etc_fd, const char *hashed_password) {
952 _cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
953 _cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
954 int r;
955 bool found = false;
956
957 r = fopen_temporary_at_label(etc_fd, "shadow", "shadow", &shadow, &shadow_tmp);
958 if (r < 0)
959 return r;
960
961 r = xfopenat(etc_fd, "shadow", "re", O_NOFOLLOW, &original);
962 if (r < 0 && r != -ENOENT)
963 return r;
964
965 if (original) {
966 struct spwd *i;
967
968 r = copy_rights(fileno(original), fileno(shadow));
969 if (r < 0)
970 return r;
971
972 while ((r = fgetspent_sane(original, &i)) > 0) {
973
974 if (streq(i->sp_namp, "root")) {
975 if (hashed_password) {
976 i->sp_pwdp = (char *) hashed_password;
977 i->sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
978 }
979 found = true;
980 }
981
982 r = putspent_sane(i, shadow);
983 if (r < 0)
984 return r;
985 }
986 if (r < 0)
987 return r;
988
989 } else {
990 r = fchmod(fileno(shadow), 0000);
991 if (r < 0)
992 return -errno;
993 }
994
995 if (!found) {
996 struct spwd root = {
997 .sp_namp = (char*) "root",
998 .sp_pwdp = (char *) (hashed_password ?: PASSWORD_LOCKED_AND_INVALID),
999 .sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY),
1000 .sp_min = -1,
1001 .sp_max = -1,
1002 .sp_warn = -1,
1003 .sp_inact = -1,
1004 .sp_expire = -1,
1005 .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
1006 };
1007
1008 if (errno != ENOENT)
1009 return -errno;
1010
1011 r = putspent_sane(&root, shadow);
1012 if (r < 0)
1013 return r;
1014 }
1015
1016 r = fflush_sync_and_check(shadow);
1017 if (r < 0)
1018 return r;
1019
1020 r = renameat_and_apply_smack_floor_label(etc_fd, shadow_tmp, etc_fd, "shadow");
1021 if (r < 0)
1022 return r;
1023
1024 return 0;
1025 }
1026
1027 static int process_root_account(int rfd, sd_varlink **mute_console_link) {
1028 _cleanup_close_ int pfd = -EBADF;
1029 _cleanup_(release_lock_file) LockFile lock = LOCK_FILE_INIT;
1030 _cleanup_(erase_and_freep) char *_hashed_password = NULL;
1031 const char *password, *hashed_password;
1032 int k = 0, r;
1033
1034 assert(rfd >= 0);
1035
1036 pfd = chase_and_open_parent_at(rfd, "/etc/passwd",
1037 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1038 NULL);
1039 if (pfd < 0)
1040 return log_error_errno(pfd, "Failed to chase /etc/passwd: %m");
1041
1042 /* Ensure that passwd and shadow are in the same directory and are not symlinks. */
1043
1044 FOREACH_STRING(s, "passwd", "shadow") {
1045 r = verify_regular_at(pfd, s, /* follow = */ false);
1046 if (r < 0 && r != -ENOENT)
1047 return log_error_errno(r, "Verification of /etc/%s being regular file failed: %m", s);
1048
1049 r = should_configure(pfd, s);
1050 if (r < 0)
1051 return r;
1052
1053 k += r;
1054 }
1055
1056 if (k == 0) {
1057 log_debug("Found /etc/passwd and /etc/shadow, assuming root account has been initialized.");
1058 return 0;
1059 }
1060
1061 r = make_lock_file_at(pfd, ETC_PASSWD_LOCK_FILENAME, LOCK_EX, &lock);
1062 if (r < 0)
1063 return log_error_errno(r, "Failed to take a lock on /etc/passwd: %m");
1064
1065 k = dir_fd_is_root(rfd);
1066 if (k < 0)
1067 return log_error_errno(k, "Failed to check if directory file descriptor is root: %m");
1068
1069 if (arg_copy_root_shell && k == 0) {
1070 _cleanup_free_ struct passwd *p = NULL;
1071
1072 r = getpwnam_malloc("root", &p);
1073 if (r < 0)
1074 return log_error_errno(r, "Failed to find passwd entry for root: %m");
1075
1076 r = free_and_strdup(&arg_root_shell, p->pw_shell);
1077 if (r < 0)
1078 return log_oom();
1079 }
1080
1081 r = prompt_root_shell(rfd, mute_console_link);
1082 if (r < 0)
1083 return r;
1084
1085 if (arg_copy_root_password && k == 0) {
1086 struct spwd *p;
1087
1088 errno = 0;
1089 p = getspnam("root");
1090 if (!p)
1091 return log_error_errno(errno_or_else(EIO), "Failed to find shadow entry for root: %m");
1092
1093 r = free_and_strdup(&arg_root_password, p->sp_pwdp);
1094 if (r < 0)
1095 return log_oom();
1096
1097 arg_root_password_is_hashed = true;
1098 }
1099
1100 r = prompt_root_password(rfd, mute_console_link);
1101 if (r < 0)
1102 return r;
1103
1104 if (arg_root_password && arg_root_password_is_hashed) {
1105 password = PASSWORD_SEE_SHADOW;
1106 hashed_password = arg_root_password;
1107 } else if (arg_root_password) {
1108 r = hash_password(arg_root_password, &_hashed_password);
1109 if (r < 0)
1110 return log_error_errno(r, "Failed to hash password: %m");
1111
1112 password = PASSWORD_SEE_SHADOW;
1113 hashed_password = _hashed_password;
1114
1115 } else if (arg_delete_root_password) {
1116 password = PASSWORD_SEE_SHADOW;
1117 hashed_password = PASSWORD_NONE;
1118 } else if (!arg_root_password && arg_prompt_root_password) {
1119 /* If the user was prompted, but no password was supplied, lock the account. */
1120 password = PASSWORD_SEE_SHADOW;
1121 hashed_password = PASSWORD_LOCKED_AND_INVALID;
1122 } else
1123 /* Leave the password as is. */
1124 password = hashed_password = NULL;
1125
1126 /* Don't create/modify passwd and shadow if there's nothing to do. */
1127 if (!(password || hashed_password || arg_root_shell)) {
1128 log_debug("Initialization of root account was not requested, skipping.");
1129 return 0;
1130 }
1131
1132 r = write_root_passwd(rfd, pfd, password, arg_root_shell);
1133 if (r < 0)
1134 return log_error_errno(r, "Failed to write /etc/passwd: %m");
1135
1136 log_info("/etc/passwd written.");
1137
1138 r = write_root_shadow(pfd, hashed_password);
1139 if (r < 0)
1140 return log_error_errno(r, "Failed to write /etc/shadow: %m");
1141
1142 log_info("/etc/shadow written.");
1143 return 0;
1144 }
1145
1146 static int process_kernel_cmdline(int rfd) {
1147 _cleanup_close_ int pfd = -EBADF;
1148 _cleanup_free_ char *f = NULL;
1149 int r;
1150
1151 assert(rfd >= 0);
1152
1153 pfd = chase_and_open_parent_at(rfd, "/etc/kernel/cmdline",
1154 CHASE_AT_RESOLVE_IN_ROOT|CHASE_MKDIR_0755|CHASE_WARN|CHASE_NOFOLLOW,
1155 &f);
1156 if (pfd < 0)
1157 return log_error_errno(pfd, "Failed to chase /etc/kernel/cmdline: %m");
1158
1159 r = should_configure(pfd, f);
1160 if (r == 0)
1161 log_debug("Found /etc/kernel/cmdline, assuming kernel command line has been configured.");
1162 if (r <= 0)
1163 return r;
1164
1165 if (!arg_kernel_cmdline) {
1166 log_debug("Creation of /etc/kernel/cmdline was not requested, skipping.");
1167 return 0;
1168 }
1169
1170 r = write_string_file_at(pfd, "cmdline", arg_kernel_cmdline,
1171 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL);
1172 if (r < 0)
1173 return log_error_errno(r, "Failed to write /etc/kernel/cmdline: %m");
1174
1175 log_info("/etc/kernel/cmdline written.");
1176 return 0;
1177 }
1178
1179 static int reset_one(int rfd, const char *path) {
1180 _cleanup_close_ int pfd = -EBADF;
1181 _cleanup_free_ char *f = NULL;
1182
1183 assert(rfd >= 0);
1184 assert(path);
1185
1186 pfd = chase_and_open_parent_at(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_WARN|CHASE_NOFOLLOW, &f);
1187 if (pfd == -ENOENT)
1188 return 0;
1189 if (pfd < 0)
1190 return log_error_errno(pfd, "Failed to resolve %s: %m", path);
1191
1192 if (unlinkat(pfd, f, 0) < 0)
1193 return errno == ENOENT ? 0 : log_error_errno(errno, "Failed to remove %s: %m", path);
1194
1195 log_info("Removed %s", path);
1196 return 0;
1197 }
1198
1199 static int process_reset(int rfd) {
1200 int r;
1201
1202 assert(rfd >= 0);
1203
1204 if (!arg_reset)
1205 return 0;
1206
1207 FOREACH_STRING(p,
1208 etc_locale_conf(),
1209 etc_vconsole_conf(),
1210 etc_hostname(),
1211 "/etc/machine-id",
1212 "/etc/kernel/cmdline",
1213 etc_localtime()) {
1214 r = reset_one(rfd, p);
1215 if (r < 0)
1216 return r;
1217 }
1218
1219 return 0;
1220 }
1221
1222 static int help(void) {
1223 _cleanup_free_ char *link = NULL;
1224 int r;
1225
1226 r = terminal_urlify_man("systemd-firstboot", "1", &link);
1227 if (r < 0)
1228 return log_oom();
1229
1230 printf("%1$s [OPTIONS...]\n"
1231 "\n%3$sConfigures basic settings of the system.%4$s\n\n"
1232 " -h --help Show this help\n"
1233 " --version Show package version\n"
1234 " --root=PATH Operate on an alternate filesystem root\n"
1235 " --image=PATH Operate on disk image as filesystem root\n"
1236 " --image-policy=POLICY Specify disk image dissection policy\n"
1237 " --locale=LOCALE Set primary locale (LANG=)\n"
1238 " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
1239 " --keymap=KEYMAP Set keymap\n"
1240 " --timezone=TIMEZONE Set timezone\n"
1241 " --hostname=NAME Set hostname\n"
1242 " --setup-machine-id Set a random machine ID\n"
1243 " --machine-id=ID Set specified machine ID\n"
1244 " --root-password=PASSWORD Set root password from plaintext password\n"
1245 " --root-password-file=FILE Set root password from file\n"
1246 " --root-password-hashed=HASH Set root password from hashed password\n"
1247 " --root-shell=SHELL Set root shell\n"
1248 " --kernel-command-line=CMDLINE\n"
1249 " Set kernel command line\n"
1250 " --prompt-locale Prompt the user for locale settings\n"
1251 " --prompt-keymap Prompt the user for keymap settings\n"
1252 " --prompt-keymap-auto Prompt the user for keymap settings if invoked\n"
1253 " on local console\n"
1254 " --prompt-timezone Prompt the user for timezone\n"
1255 " --prompt-hostname Prompt the user for hostname\n"
1256 " --prompt-root-password Prompt the user for root password\n"
1257 " --prompt-root-shell Prompt the user for root shell\n"
1258 " --prompt Prompt for all of the above\n"
1259 " --copy-locale Copy locale from host\n"
1260 " --copy-keymap Copy keymap from host\n"
1261 " --copy-timezone Copy timezone from host\n"
1262 " --copy-root-password Copy root password from host\n"
1263 " --copy-root-shell Copy root shell from host\n"
1264 " --copy Copy locale, keymap, timezone, root password\n"
1265 " --force Overwrite existing files\n"
1266 " --delete-root-password Delete root password\n"
1267 " --welcome=no Disable the welcome text\n"
1268 " --chrome=no Don't show color bar at top and bottom of\n"
1269 " terminal\n"
1270 " --mute-console=yes Tell kernel/PID 1 to not write to the console\n"
1271 " while running\n"
1272 " --reset Remove existing files\n"
1273 "\nSee the %2$s for details.\n",
1274 program_invocation_short_name,
1275 link,
1276 ansi_highlight(),
1277 ansi_normal());
1278
1279 return 0;
1280 }
1281
1282 static int parse_argv(int argc, char *argv[]) {
1283
1284 enum {
1285 ARG_VERSION = 0x100,
1286 ARG_ROOT,
1287 ARG_IMAGE,
1288 ARG_IMAGE_POLICY,
1289 ARG_LOCALE,
1290 ARG_LOCALE_MESSAGES,
1291 ARG_KEYMAP,
1292 ARG_TIMEZONE,
1293 ARG_HOSTNAME,
1294 ARG_SETUP_MACHINE_ID,
1295 ARG_MACHINE_ID,
1296 ARG_ROOT_PASSWORD,
1297 ARG_ROOT_PASSWORD_FILE,
1298 ARG_ROOT_PASSWORD_HASHED,
1299 ARG_ROOT_SHELL,
1300 ARG_KERNEL_COMMAND_LINE,
1301 ARG_PROMPT,
1302 ARG_PROMPT_LOCALE,
1303 ARG_PROMPT_KEYMAP,
1304 ARG_PROMPT_KEYMAP_AUTO,
1305 ARG_PROMPT_TIMEZONE,
1306 ARG_PROMPT_HOSTNAME,
1307 ARG_PROMPT_ROOT_PASSWORD,
1308 ARG_PROMPT_ROOT_SHELL,
1309 ARG_COPY,
1310 ARG_COPY_LOCALE,
1311 ARG_COPY_KEYMAP,
1312 ARG_COPY_TIMEZONE,
1313 ARG_COPY_ROOT_PASSWORD,
1314 ARG_COPY_ROOT_SHELL,
1315 ARG_FORCE,
1316 ARG_DELETE_ROOT_PASSWORD,
1317 ARG_WELCOME,
1318 ARG_CHROME,
1319 ARG_RESET,
1320 ARG_MUTE_CONSOLE,
1321 };
1322
1323 static const struct option options[] = {
1324 { "help", no_argument, NULL, 'h' },
1325 { "version", no_argument, NULL, ARG_VERSION },
1326 { "root", required_argument, NULL, ARG_ROOT },
1327 { "image", required_argument, NULL, ARG_IMAGE },
1328 { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
1329 { "locale", required_argument, NULL, ARG_LOCALE },
1330 { "locale-messages", required_argument, NULL, ARG_LOCALE_MESSAGES },
1331 { "keymap", required_argument, NULL, ARG_KEYMAP },
1332 { "timezone", required_argument, NULL, ARG_TIMEZONE },
1333 { "hostname", required_argument, NULL, ARG_HOSTNAME },
1334 { "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID },
1335 { "machine-id", required_argument, NULL, ARG_MACHINE_ID },
1336 { "root-password", required_argument, NULL, ARG_ROOT_PASSWORD },
1337 { "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE },
1338 { "root-password-hashed", required_argument, NULL, ARG_ROOT_PASSWORD_HASHED },
1339 { "root-shell", required_argument, NULL, ARG_ROOT_SHELL },
1340 { "kernel-command-line", required_argument, NULL, ARG_KERNEL_COMMAND_LINE },
1341 { "prompt", no_argument, NULL, ARG_PROMPT },
1342 { "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE },
1343 { "prompt-keymap", no_argument, NULL, ARG_PROMPT_KEYMAP },
1344 { "prompt-keymap-auto", no_argument, NULL, ARG_PROMPT_KEYMAP_AUTO },
1345 { "prompt-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE },
1346 { "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME },
1347 { "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD },
1348 { "prompt-root-shell", no_argument, NULL, ARG_PROMPT_ROOT_SHELL },
1349 { "copy", no_argument, NULL, ARG_COPY },
1350 { "copy-locale", no_argument, NULL, ARG_COPY_LOCALE },
1351 { "copy-keymap", no_argument, NULL, ARG_COPY_KEYMAP },
1352 { "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE },
1353 { "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD },
1354 { "copy-root-shell", no_argument, NULL, ARG_COPY_ROOT_SHELL },
1355 { "force", no_argument, NULL, ARG_FORCE },
1356 { "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD },
1357 { "welcome", required_argument, NULL, ARG_WELCOME },
1358 { "chrome", required_argument, NULL, ARG_CHROME },
1359 { "reset", no_argument, NULL, ARG_RESET },
1360 { "mute-console", required_argument, NULL, ARG_MUTE_CONSOLE },
1361 {}
1362 };
1363
1364 int r, c;
1365
1366 assert(argc >= 0);
1367 assert(argv);
1368
1369 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
1370
1371 switch (c) {
1372
1373 case 'h':
1374 return help();
1375
1376 case ARG_VERSION:
1377 return version();
1378
1379 case ARG_ROOT:
1380 r = parse_path_argument(optarg, true, &arg_root);
1381 if (r < 0)
1382 return r;
1383 break;
1384
1385 case ARG_IMAGE:
1386 r = parse_path_argument(optarg, false, &arg_image);
1387 if (r < 0)
1388 return r;
1389 break;
1390
1391 case ARG_IMAGE_POLICY:
1392 r = parse_image_policy_argument(optarg, &arg_image_policy);
1393 if (r < 0)
1394 return r;
1395 break;
1396
1397 case ARG_LOCALE:
1398 r = free_and_strdup(&arg_locale, optarg);
1399 if (r < 0)
1400 return log_oom();
1401
1402 break;
1403
1404 case ARG_LOCALE_MESSAGES:
1405 r = free_and_strdup(&arg_locale_messages, optarg);
1406 if (r < 0)
1407 return log_oom();
1408
1409 break;
1410
1411 case ARG_KEYMAP:
1412 if (!keymap_is_valid(optarg))
1413 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1414 "Keymap %s is not valid.", optarg);
1415
1416 r = free_and_strdup(&arg_keymap, optarg);
1417 if (r < 0)
1418 return log_oom();
1419
1420 break;
1421
1422 case ARG_TIMEZONE:
1423 if (!timezone_is_valid(optarg, LOG_ERR))
1424 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1425 "Timezone %s is not valid.", optarg);
1426
1427 r = free_and_strdup(&arg_timezone, optarg);
1428 if (r < 0)
1429 return log_oom();
1430
1431 break;
1432
1433 case ARG_ROOT_PASSWORD:
1434 r = free_and_strdup(&arg_root_password, optarg);
1435 if (r < 0)
1436 return log_oom();
1437
1438 arg_root_password_is_hashed = false;
1439 break;
1440
1441 case ARG_ROOT_PASSWORD_FILE:
1442 arg_root_password = mfree(arg_root_password);
1443
1444 r = read_one_line_file(optarg, &arg_root_password);
1445 if (r < 0)
1446 return log_error_errno(r, "Failed to read %s: %m", optarg);
1447
1448 arg_root_password_is_hashed = false;
1449 break;
1450
1451 case ARG_ROOT_PASSWORD_HASHED:
1452 r = free_and_strdup(&arg_root_password, optarg);
1453 if (r < 0)
1454 return log_oom();
1455
1456 arg_root_password_is_hashed = true;
1457 break;
1458
1459 case ARG_ROOT_SHELL:
1460 r = free_and_strdup(&arg_root_shell, optarg);
1461 if (r < 0)
1462 return log_oom();
1463
1464 break;
1465
1466 case ARG_HOSTNAME:
1467 if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT|VALID_HOSTNAME_QUESTION_MARK))
1468 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1469 "Host name %s is not valid.", optarg);
1470
1471 r = free_and_strdup(&arg_hostname, optarg);
1472 if (r < 0)
1473 return log_oom();
1474
1475 hostname_cleanup(arg_hostname);
1476 break;
1477
1478 case ARG_SETUP_MACHINE_ID:
1479 r = sd_id128_randomize(&arg_machine_id);
1480 if (r < 0)
1481 return log_error_errno(r, "Failed to generate randomized machine ID: %m");
1482
1483 break;
1484
1485 case ARG_MACHINE_ID:
1486 r = sd_id128_from_string(optarg, &arg_machine_id);
1487 if (r < 0)
1488 return log_error_errno(r, "Failed to parse machine id %s.", optarg);
1489
1490 break;
1491
1492 case ARG_KERNEL_COMMAND_LINE:
1493 r = free_and_strdup(&arg_kernel_cmdline, optarg);
1494 if (r < 0)
1495 return log_oom();
1496
1497 break;
1498
1499 case ARG_PROMPT:
1500 arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname =
1501 arg_prompt_root_password = arg_prompt_root_shell = true;
1502 arg_prompt_keymap_auto = false;
1503 break;
1504
1505 case ARG_PROMPT_LOCALE:
1506 arg_prompt_locale = true;
1507 break;
1508
1509 case ARG_PROMPT_KEYMAP:
1510 arg_prompt_keymap = true;
1511 arg_prompt_keymap_auto = false;
1512 break;
1513
1514 case ARG_PROMPT_KEYMAP_AUTO:
1515 arg_prompt_keymap_auto = true;
1516 break;
1517
1518 case ARG_PROMPT_TIMEZONE:
1519 arg_prompt_timezone = true;
1520 break;
1521
1522 case ARG_PROMPT_HOSTNAME:
1523 arg_prompt_hostname = true;
1524 break;
1525
1526 case ARG_PROMPT_ROOT_PASSWORD:
1527 arg_prompt_root_password = true;
1528 break;
1529
1530 case ARG_PROMPT_ROOT_SHELL:
1531 arg_prompt_root_shell = true;
1532 break;
1533
1534 case ARG_COPY:
1535 arg_copy_locale = arg_copy_keymap = arg_copy_timezone = arg_copy_root_password =
1536 arg_copy_root_shell = true;
1537 break;
1538
1539 case ARG_COPY_LOCALE:
1540 arg_copy_locale = true;
1541 break;
1542
1543 case ARG_COPY_KEYMAP:
1544 arg_copy_keymap = true;
1545 break;
1546
1547 case ARG_COPY_TIMEZONE:
1548 arg_copy_timezone = true;
1549 break;
1550
1551 case ARG_COPY_ROOT_PASSWORD:
1552 arg_copy_root_password = true;
1553 break;
1554
1555 case ARG_COPY_ROOT_SHELL:
1556 arg_copy_root_shell = true;
1557 break;
1558
1559 case ARG_FORCE:
1560 arg_force = true;
1561 break;
1562
1563 case ARG_DELETE_ROOT_PASSWORD:
1564 arg_delete_root_password = true;
1565 break;
1566
1567 case ARG_WELCOME:
1568 r = parse_boolean(optarg);
1569 if (r < 0)
1570 return log_error_errno(r, "Failed to parse --welcome= argument: %s", optarg);
1571
1572 arg_welcome = r;
1573 break;
1574
1575 case ARG_CHROME:
1576 r = parse_boolean_argument("--chrome=", optarg, &arg_chrome);
1577 if (r < 0)
1578 return r;
1579
1580 break;
1581
1582 case ARG_RESET:
1583 arg_reset = true;
1584 break;
1585
1586 case ARG_MUTE_CONSOLE:
1587 r = parse_boolean_argument("--mute-console=", optarg, &arg_mute_console);
1588 if (r < 0)
1589 return r;
1590
1591 break;
1592
1593 case '?':
1594 return -EINVAL;
1595
1596 default:
1597 assert_not_reached();
1598 }
1599
1600 if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
1601 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1602 "--delete-root-password cannot be combined with other root password options.");
1603
1604 if (arg_image && arg_root)
1605 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1606 "--root= and --image= cannot be used together.");
1607
1608 if (!sd_id128_is_null(arg_machine_id) && !(arg_image || arg_root) && !arg_force)
1609 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1610 "--machine-id=/--setup-machine-id only works with --root= or --image=.");
1611
1612 return 1;
1613 }
1614
1615 static int reload_system_manager(sd_bus **bus) {
1616 int r;
1617
1618 assert(bus);
1619
1620 if (!*bus) {
1621 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
1622 if (r < 0)
1623 return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
1624 }
1625
1626 r = bus_service_manager_reload(*bus);
1627 if (r < 0)
1628 return r;
1629
1630 log_info("Requested manager reload to apply locale configuration.");
1631 return 0;
1632 }
1633
1634 static int reload_vconsole(sd_bus **bus) {
1635 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1636 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1637 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1638 const char *object;
1639 int r;
1640
1641 assert(bus);
1642
1643 if (!*bus) {
1644 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, RUNTIME_SCOPE_SYSTEM, bus);
1645 if (r < 0)
1646 return bus_log_connect_error(r, BUS_TRANSPORT_LOCAL, RUNTIME_SCOPE_SYSTEM);
1647 }
1648
1649 r = bus_wait_for_jobs_new(*bus, &w);
1650 if (r < 0)
1651 return log_error_errno(r, "Could not watch jobs: %m");
1652
1653 r = bus_call_method(*bus, bus_systemd_mgr, "RestartUnit", &error, &reply,
1654 "ss", "systemd-vconsole-setup.service", "replace");
1655 if (r < 0)
1656 return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
1657
1658 r = sd_bus_message_read(reply, "o", &object);
1659 if (r < 0)
1660 return bus_log_parse_error(r);
1661
1662 r = bus_wait_for_jobs_one(w, object, BUS_WAIT_JOBS_LOG_ERROR, NULL);
1663 if (r < 0)
1664 return log_error_errno(r, "Failed to wait for systemd-vconsole-setup.service/restart: %m");
1665 return 0;
1666 }
1667
1668 static int run(int argc, char *argv[]) {
1669 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1670 _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
1671 _cleanup_(umount_and_freep) char *mounted_dir = NULL;
1672 _cleanup_close_ int rfd = -EBADF;
1673 int r;
1674
1675 r = parse_argv(argc, argv);
1676 if (r <= 0)
1677 return r;
1678
1679 log_setup();
1680
1681 umask(0022);
1682
1683 bool offline = arg_root || arg_image;
1684
1685 if (!offline) {
1686 /* If we are called without --root=/--image= let's honour the systemd.firstboot kernel
1687 * command line option, because we are called to provision the host with basic settings (as
1688 * opposed to some other file system tree/image) */
1689
1690 bool enabled;
1691 r = proc_cmdline_get_bool("systemd.firstboot", /* flags = */ 0, &enabled);
1692 if (r < 0)
1693 return log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring: %m");
1694 if (r > 0 && !enabled) {
1695 log_debug("Found systemd.firstboot=no kernel command line argument, turning off all prompts.");
1696 arg_prompt_locale = arg_prompt_keymap = arg_prompt_keymap_auto = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = arg_prompt_root_shell = false;
1697 }
1698 }
1699
1700 r = mac_init();
1701 if (r < 0)
1702 return r;
1703
1704 if (arg_image) {
1705 assert(!arg_root);
1706
1707 r = mount_image_privately_interactively(
1708 arg_image,
1709 arg_image_policy,
1710 DISSECT_IMAGE_GENERIC_ROOT |
1711 DISSECT_IMAGE_REQUIRE_ROOT |
1712 DISSECT_IMAGE_VALIDATE_OS |
1713 DISSECT_IMAGE_RELAX_VAR_CHECK |
1714 DISSECT_IMAGE_FSCK |
1715 DISSECT_IMAGE_GROWFS |
1716 DISSECT_IMAGE_ALLOW_USERSPACE_VERITY,
1717 &mounted_dir,
1718 &rfd,
1719 &loop_device);
1720 if (r < 0)
1721 return r;
1722
1723 arg_root = strdup(mounted_dir);
1724 if (!arg_root)
1725 return log_oom();
1726 } else {
1727 rfd = open(empty_to_root(arg_root), O_DIRECTORY|O_CLOEXEC);
1728 if (rfd < 0)
1729 return log_error_errno(errno, "Failed to open %s: %m", empty_to_root(arg_root));
1730 }
1731
1732 LOG_SET_PREFIX(arg_image ?: arg_root);
1733 DEFER_VOID_CALL(chrome_hide);
1734
1735 /* We check these conditions here instead of in parse_argv() so that we can take the root directory
1736 * into account. */
1737
1738 if (arg_keymap && !keymap_is_ok(arg_keymap, FD_TO_PTR(rfd)))
1739 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Keymap %s is not installed.", arg_keymap);
1740 if (arg_locale && !locale_is_ok(arg_locale, FD_TO_PTR(rfd)))
1741 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
1742 if (arg_locale_messages && !locale_is_ok(arg_locale_messages, FD_TO_PTR(rfd)))
1743 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
1744
1745 if (arg_root_shell) {
1746 r = find_shell(rfd, arg_root_shell);
1747 if (r < 0)
1748 return r;
1749 }
1750
1751 r = process_reset(rfd);
1752 if (r < 0)
1753 return r;
1754
1755 _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *mute_console_link = NULL;
1756 r = process_locale(rfd, &mute_console_link);
1757 if (r < 0)
1758 return r;
1759 if (r > 0 && !offline)
1760 (void) reload_system_manager(&bus);
1761
1762 r = process_keymap(rfd, &mute_console_link);
1763 if (r < 0)
1764 return r;
1765 if (r > 0 && !offline)
1766 (void) reload_vconsole(&bus);
1767
1768 r = process_timezone(rfd, &mute_console_link);
1769 if (r < 0)
1770 return r;
1771
1772 r = process_hostname(rfd, &mute_console_link);
1773 if (r < 0)
1774 return r;
1775
1776 r = process_root_account(rfd, &mute_console_link);
1777 if (r < 0)
1778 return r;
1779
1780 r = process_kernel_cmdline(rfd);
1781 if (r < 0)
1782 return r;
1783
1784 r = process_machine_id(rfd);
1785 if (r < 0)
1786 return r;
1787
1788 return 0;
1789 }
1790
1791 DEFINE_MAIN_FUNCTION(run);