Merge pull request #15893 from DaanDeMeyer/firstboot-overwrite
systemd-firstboot: Add --force, --delete-root-password and --root-password-is-hashed options
This commit is contained in:
@@ -256,8 +256,6 @@ Features:
|
||||
* systemd-firstboot: teach it dissector magic, so that you can point it to some
|
||||
disk image and it will just set everything in it all behind the scenes.
|
||||
|
||||
* systemd-firstboot: add --force mode that replaces existing configuration.
|
||||
|
||||
* We should probably replace /var/log/README, /etc/rc.d/README with symlinks
|
||||
that are linked to these places instead of copied. After all they are
|
||||
constant vendor data.
|
||||
|
||||
+36
-10
@@ -150,18 +150,27 @@
|
||||
<varlistentry>
|
||||
<term><option>--root-password=<replaceable>PASSWORD</replaceable></option></term>
|
||||
<term><option>--root-password-file=<replaceable>PATH</replaceable></option></term>
|
||||
<term><option>--root-password-hashed=<replaceable>HASHED_PASSWORD</replaceable></option></term>
|
||||
|
||||
<listitem><para>Sets the password of the system's root user.
|
||||
This creates a
|
||||
<listitem><para>Sets the password of the system's root user. This creates a
|
||||
<citerefentry project='die-net'><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
file. This setting exists in two forms:
|
||||
<option>--root-password=</option> accepts the password to set
|
||||
directly on the command line, and
|
||||
<option>--root-password-file=</option> reads it from a file.
|
||||
Note that it is not recommended to specify passwords on the
|
||||
command line, as other users might be able to see them simply
|
||||
by invoking
|
||||
<citerefentry project='die-net'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
|
||||
file. This setting exists in three forms: <option>--root-password=</option> accepts the password to
|
||||
set directly on the command line, <option>--root-password-file=</option> reads it from a file and
|
||||
<option>--root-password-hashed=</option> accepts an already hashed password on the command line. See
|
||||
<citerefentry project='die-net'><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for more information on the format of the hashed password. Note that it is not recommended to specify
|
||||
plaintext passwords on the command line, as other users might be able to see them simply by invoking
|
||||
<citerefentry project='die-net'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--kernel-command-line=<replaceable>CMDLINE</replaceable></option></term>
|
||||
|
||||
<listitem><para>Sets the system's kernel command line. This controls the
|
||||
<filename>/etc/kernel/cmdline</filename> file which is used by
|
||||
<citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -221,6 +230,23 @@
|
||||
<option>--root=</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--force</option></term>
|
||||
|
||||
<listitem><para>systemd-firstboot doesn't modify existing files unless <option>--force</option>
|
||||
is specified. For modifications to <filename>/etc/passwd</filename> and
|
||||
<filename>/etc/shadow</filename>, systemd-firstboot only modifies the entry of the
|
||||
<literal>root</literal> user instead of overwriting the entire file.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--delete-root-password</option></term>
|
||||
|
||||
<listitem><para>Removes the password of the system's root user, enabling login as root without a
|
||||
password unless the root account is locked. Note that this is extremely insecure and hence this
|
||||
option should not be used lightly.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
||||
@@ -1187,3 +1187,25 @@ int warn_file_is_world_accessible(const char *filename, struct stat *st, const c
|
||||
filename, st->st_mode & 07777);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sync_rights(int from, int to) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(from, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
return fchmod_and_chown(to, st.st_mode & 07777, st.st_uid, st.st_gid);
|
||||
}
|
||||
|
||||
int rename_and_apply_smack_floor_label(const char *from, const char *to) {
|
||||
int r = 0;
|
||||
if (rename(from, to) < 0)
|
||||
return -errno;
|
||||
|
||||
#ifdef SMACK_RUN_LABEL
|
||||
r = mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -106,3 +106,7 @@ static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
|
||||
int safe_fgetc(FILE *f, char *ret);
|
||||
|
||||
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
|
||||
|
||||
int sync_rights(int from, int to);
|
||||
|
||||
int rename_and_apply_smack_floor_label(const char *temp_path, const char *dest_path);
|
||||
|
||||
+283
-94
@@ -30,6 +30,7 @@
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "time-util.h"
|
||||
#include "tmpfile-util-label.h"
|
||||
#include "umask-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
@@ -41,6 +42,7 @@ static char *arg_timezone = NULL;
|
||||
static char *arg_hostname = NULL;
|
||||
static sd_id128_t arg_machine_id = {};
|
||||
static char *arg_root_password = NULL;
|
||||
static char *arg_kernel_cmdline = NULL;
|
||||
static bool arg_prompt_locale = false;
|
||||
static bool arg_prompt_keymap = false;
|
||||
static bool arg_prompt_timezone = false;
|
||||
@@ -50,6 +52,9 @@ static bool arg_copy_locale = false;
|
||||
static bool arg_copy_keymap = false;
|
||||
static bool arg_copy_timezone = false;
|
||||
static bool arg_copy_root_password = false;
|
||||
static bool arg_force = false;
|
||||
static bool arg_delete_root_password = false;
|
||||
static bool arg_root_password_is_hashed = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_locale, freep);
|
||||
@@ -273,7 +278,7 @@ static int process_locale(void) {
|
||||
int r;
|
||||
|
||||
etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf");
|
||||
if (laccess(etc_localeconf, F_OK) >= 0)
|
||||
if (laccess(etc_localeconf, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
if (arg_copy_locale && arg_root) {
|
||||
@@ -340,7 +345,7 @@ static int process_keymap(void) {
|
||||
int r;
|
||||
|
||||
etc_vconsoleconf = prefix_roota(arg_root, "/etc/vconsole.conf");
|
||||
if (laccess(etc_vconsoleconf, F_OK) >= 0)
|
||||
if (laccess(etc_vconsoleconf, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
if (arg_copy_keymap && arg_root) {
|
||||
@@ -412,7 +417,7 @@ static int process_timezone(void) {
|
||||
int r;
|
||||
|
||||
etc_localtime = prefix_roota(arg_root, "/etc/localtime");
|
||||
if (laccess(etc_localtime, F_OK) >= 0)
|
||||
if (laccess(etc_localtime, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
if (arg_copy_timezone && arg_root) {
|
||||
@@ -492,7 +497,7 @@ static int process_hostname(void) {
|
||||
int r;
|
||||
|
||||
etc_hostname = prefix_roota(arg_root, "/etc/hostname");
|
||||
if (laccess(etc_hostname, F_OK) >= 0)
|
||||
if (laccess(etc_hostname, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
r = prompt_hostname();
|
||||
@@ -503,7 +508,8 @@ static int process_hostname(void) {
|
||||
return 0;
|
||||
|
||||
r = write_string_file(etc_hostname, arg_hostname,
|
||||
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755);
|
||||
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755 |
|
||||
(arg_force ? WRITE_STRING_FILE_ATOMIC : 0));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write %s: %m", etc_hostname);
|
||||
|
||||
@@ -517,14 +523,15 @@ static int process_machine_id(void) {
|
||||
int r;
|
||||
|
||||
etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
|
||||
if (laccess(etc_machine_id, F_OK) >= 0)
|
||||
if (laccess(etc_machine_id, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
if (sd_id128_is_null(arg_machine_id))
|
||||
return 0;
|
||||
|
||||
r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id),
|
||||
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755);
|
||||
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755 |
|
||||
(arg_force ? WRITE_STRING_FILE_ATOMIC : 0));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write machine id: %m");
|
||||
|
||||
@@ -533,7 +540,7 @@ static int process_machine_id(void) {
|
||||
}
|
||||
|
||||
static int prompt_root_password(void) {
|
||||
const char *msg1, *msg2, *etc_shadow;
|
||||
const char *msg1, *msg2;
|
||||
int r;
|
||||
|
||||
if (arg_root_password)
|
||||
@@ -542,10 +549,6 @@ static int prompt_root_password(void) {
|
||||
if (!arg_prompt_root_password)
|
||||
return 0;
|
||||
|
||||
etc_shadow = prefix_roota(arg_root, "/etc/shadow");
|
||||
if (laccess(etc_shadow, F_OK) >= 0)
|
||||
return 0;
|
||||
|
||||
print_welcome();
|
||||
putchar('\n');
|
||||
|
||||
@@ -586,45 +589,145 @@ static int prompt_root_password(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_root_shadow(const char *path, const struct spwd *p) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
static int write_root_passwd(const char *passwd_path, const char *password) {
|
||||
_cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
|
||||
_cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(p);
|
||||
|
||||
RUN_WITH_UMASK(0777)
|
||||
f = fopen(path, "wex");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
r = putspent_sane(p, f);
|
||||
r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return fflush_sync_and_check(f);
|
||||
original = fopen(passwd_path, "re");
|
||||
if (original) {
|
||||
struct passwd *i;
|
||||
|
||||
r = sync_rights(fileno(original), fileno(passwd));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = fgetpwent_sane(original, &i)) > 0) {
|
||||
|
||||
if (streq(i->pw_name, "root"))
|
||||
i->pw_passwd = (char *) password;
|
||||
|
||||
r = putpwent_sane(i, passwd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
} else {
|
||||
struct passwd root = {
|
||||
.pw_name = (char *) "root",
|
||||
.pw_passwd = (char *) password,
|
||||
.pw_uid = 0,
|
||||
.pw_gid = 0,
|
||||
.pw_gecos = (char *) "Super User",
|
||||
.pw_dir = (char *) "/root",
|
||||
.pw_shell = (char *) "/bin/sh",
|
||||
};
|
||||
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
r = fchmod(fileno(passwd), 0000);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = putpwent_sane(&root, passwd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fflush_sync_and_check(passwd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = rename_and_apply_smack_floor_label(passwd_tmp, passwd_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_root_shadow(const char *shadow_path, const char *hashed_password) {
|
||||
_cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
|
||||
_cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
|
||||
int r;
|
||||
|
||||
r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
original = fopen(shadow_path, "re");
|
||||
if (original) {
|
||||
struct spwd *i;
|
||||
|
||||
r = sync_rights(fileno(original), fileno(shadow));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = fgetspent_sane(original, &i)) > 0) {
|
||||
|
||||
if (streq(i->sp_namp, "root")) {
|
||||
i->sp_pwdp = (char *) hashed_password;
|
||||
i->sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
|
||||
}
|
||||
|
||||
r = putspent_sane(i, shadow);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
} else {
|
||||
struct spwd root = {
|
||||
.sp_namp = (char*) "root",
|
||||
.sp_pwdp = (char *) hashed_password,
|
||||
.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY),
|
||||
.sp_min = -1,
|
||||
.sp_max = -1,
|
||||
.sp_warn = -1,
|
||||
.sp_inact = -1,
|
||||
.sp_expire = -1,
|
||||
.sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
|
||||
};
|
||||
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
r = fchmod(fileno(shadow), 0000);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
r = putspent_sane(&root, shadow);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = fflush_sync_and_check(shadow);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = rename_and_apply_smack_floor_label(shadow_tmp, shadow_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_root_password(void) {
|
||||
|
||||
struct spwd item = {
|
||||
.sp_namp = (char*) "root",
|
||||
.sp_min = -1,
|
||||
.sp_max = -1,
|
||||
.sp_warn = -1,
|
||||
.sp_inact = -1,
|
||||
.sp_expire = -1,
|
||||
.sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
|
||||
};
|
||||
_cleanup_free_ char *salt = NULL;
|
||||
_cleanup_close_ int lock = -1;
|
||||
struct crypt_data cd = {};
|
||||
|
||||
const char *hashed_password;
|
||||
const char *etc_shadow;
|
||||
int r;
|
||||
|
||||
etc_shadow = prefix_roota(arg_root, "/etc/shadow");
|
||||
if (laccess(etc_shadow, F_OK) >= 0)
|
||||
if (laccess(etc_shadow, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
(void) mkdir_parents(etc_shadow, 0755);
|
||||
@@ -633,6 +736,21 @@ static int process_root_password(void) {
|
||||
if (lock < 0)
|
||||
return log_error_errno(lock, "Failed to take a lock: %m");
|
||||
|
||||
if (arg_delete_root_password) {
|
||||
const char *etc_passwd;
|
||||
|
||||
/* Mixing alloca() and other stuff that touches the stack in one expression is not portable. */
|
||||
etc_passwd = prefix_roota(arg_root, "/etc/passwd");
|
||||
|
||||
r = write_root_passwd(etc_passwd, "");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write %s: %m", etc_passwd);
|
||||
|
||||
log_info("%s written", etc_passwd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_copy_root_password && arg_root) {
|
||||
struct spwd *p;
|
||||
|
||||
@@ -646,7 +764,7 @@ static int process_root_password(void) {
|
||||
return log_error_errno(errno, "Failed to find shadow entry for root: %m");
|
||||
}
|
||||
|
||||
r = write_root_shadow(etc_shadow, p);
|
||||
r = write_root_shadow(etc_shadow, p->sp_pwdp);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write %s: %m", etc_shadow);
|
||||
|
||||
@@ -662,19 +780,24 @@ static int process_root_password(void) {
|
||||
if (!arg_root_password)
|
||||
return 0;
|
||||
|
||||
r = make_salt(&salt);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get salt: %m");
|
||||
if (arg_root_password_is_hashed)
|
||||
hashed_password = arg_root_password;
|
||||
else {
|
||||
_cleanup_free_ char *salt = NULL;
|
||||
/* hashed_password points inside cd after crypt_r returns so cd has function scope. */
|
||||
|
||||
errno = 0;
|
||||
item.sp_pwdp = crypt_r(arg_root_password, salt, &cd);
|
||||
if (!item.sp_pwdp)
|
||||
return log_error_errno(errno == 0 ? SYNTHETIC_ERRNO(EINVAL) : errno,
|
||||
"Failed to encrypt password: %m");
|
||||
r = make_salt(&salt);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get salt: %m");
|
||||
|
||||
item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
|
||||
errno = 0;
|
||||
hashed_password = crypt_r(arg_root_password, salt, &cd);
|
||||
if (!hashed_password)
|
||||
return log_error_errno(errno == 0 ? SYNTHETIC_ERRNO(EINVAL) : errno,
|
||||
"Failed to encrypt password: %m");
|
||||
}
|
||||
|
||||
r = write_root_shadow(etc_shadow, &item);
|
||||
r = write_root_shadow(etc_shadow, hashed_password);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write %s: %m", etc_shadow);
|
||||
|
||||
@@ -682,6 +805,27 @@ static int process_root_password(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_kernel_cmdline(void) {
|
||||
const char *etc_kernel_cmdline;
|
||||
int r;
|
||||
|
||||
etc_kernel_cmdline = prefix_roota(arg_root, "/etc/kernel/cmdline");
|
||||
if (laccess(etc_kernel_cmdline, F_OK) >= 0 && !arg_force)
|
||||
return 0;
|
||||
|
||||
if (!arg_kernel_cmdline)
|
||||
return 0;
|
||||
|
||||
r = write_string_file(etc_kernel_cmdline, arg_kernel_cmdline,
|
||||
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC | WRITE_STRING_FILE_MKDIR_0755 |
|
||||
(arg_force ? WRITE_STRING_FILE_ATOMIC : 0));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write %s: %m", etc_kernel_cmdline);
|
||||
|
||||
log_info("%s written.", etc_kernel_cmdline);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
@@ -692,29 +836,32 @@ static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"Configures basic settings of the system.\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --root=PATH Operate on an alternate filesystem root\n"
|
||||
" --locale=LOCALE Set primary locale (LANG=)\n"
|
||||
" --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
|
||||
" --keymap=KEYMAP Set keymap\n"
|
||||
" --timezone=TIMEZONE Set timezone\n"
|
||||
" --hostname=NAME Set hostname\n"
|
||||
" --machine-ID=ID Set machine ID\n"
|
||||
" --root-password=PASSWORD Set root password\n"
|
||||
" --root-password-file=FILE Set root password from file\n"
|
||||
" --prompt-locale Prompt the user for locale settings\n"
|
||||
" --prompt-keymap Prompt the user for keymap settings\n"
|
||||
" --prompt-timezone Prompt the user for timezone\n"
|
||||
" --prompt-hostname Prompt the user for hostname\n"
|
||||
" --prompt-root-password Prompt the user for root password\n"
|
||||
" --prompt Prompt for all of the above\n"
|
||||
" --copy-locale Copy locale from host\n"
|
||||
" --copy-keymap Copy keymap from host\n"
|
||||
" --copy-timezone Copy timezone from host\n"
|
||||
" --copy-root-password Copy root password from host\n"
|
||||
" --copy Copy locale, keymap, timezone, root password\n"
|
||||
" --setup-machine-id Generate a new random machine ID\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --root=PATH Operate on an alternate filesystem root\n"
|
||||
" --locale=LOCALE Set primary locale (LANG=)\n"
|
||||
" --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
|
||||
" --keymap=KEYMAP Set keymap\n"
|
||||
" --timezone=TIMEZONE Set timezone\n"
|
||||
" --hostname=NAME Set hostname\n"
|
||||
" --machine-ID=ID Set machine ID\n"
|
||||
" --root-password=PASSWORD Set root password from plaintext password\n"
|
||||
" --root-password-file=FILE Set root password from file\n"
|
||||
" --root-password-hashed=HASHED_PASSWORD Set root password from hashed password\n"
|
||||
" --prompt-locale Prompt the user for locale settings\n"
|
||||
" --prompt-keymap Prompt the user for keymap settings\n"
|
||||
" --prompt-timezone Prompt the user for timezone\n"
|
||||
" --prompt-hostname Prompt the user for hostname\n"
|
||||
" --prompt-root-password Prompt the user for root password\n"
|
||||
" --prompt Prompt for all of the above\n"
|
||||
" --copy-locale Copy locale from host\n"
|
||||
" --copy-keymap Copy keymap from host\n"
|
||||
" --copy-timezone Copy timezone from host\n"
|
||||
" --copy-root-password Copy root password from host\n"
|
||||
" --copy Copy locale, keymap, timezone, root password\n"
|
||||
" --setup-machine-id Generate a new random machine ID\n"
|
||||
" --force Overwrite existing files\n"
|
||||
" --delete-root-password Delete root password\n"
|
||||
"\nSee the %s for details.\n"
|
||||
, program_invocation_short_name
|
||||
, link
|
||||
@@ -736,6 +883,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_MACHINE_ID,
|
||||
ARG_ROOT_PASSWORD,
|
||||
ARG_ROOT_PASSWORD_FILE,
|
||||
ARG_ROOT_PASSWORD_HASHED,
|
||||
ARG_KERNEL_COMMAND_LINE,
|
||||
ARG_PROMPT,
|
||||
ARG_PROMPT_LOCALE,
|
||||
ARG_PROMPT_KEYMAP,
|
||||
@@ -748,32 +897,38 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_COPY_TIMEZONE,
|
||||
ARG_COPY_ROOT_PASSWORD,
|
||||
ARG_SETUP_MACHINE_ID,
|
||||
ARG_FORCE,
|
||||
ARG_DELETE_ROOT_PASSWORD,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "locale", required_argument, NULL, ARG_LOCALE },
|
||||
{ "locale-messages", required_argument, NULL, ARG_LOCALE_MESSAGES },
|
||||
{ "keymap", required_argument, NULL, ARG_KEYMAP },
|
||||
{ "timezone", required_argument, NULL, ARG_TIMEZONE },
|
||||
{ "hostname", required_argument, NULL, ARG_HOSTNAME },
|
||||
{ "machine-id", required_argument, NULL, ARG_MACHINE_ID },
|
||||
{ "root-password", required_argument, NULL, ARG_ROOT_PASSWORD },
|
||||
{ "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE },
|
||||
{ "prompt", no_argument, NULL, ARG_PROMPT },
|
||||
{ "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE },
|
||||
{ "prompt-keymap", no_argument, NULL, ARG_PROMPT_KEYMAP },
|
||||
{ "prompt-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE },
|
||||
{ "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME },
|
||||
{ "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD },
|
||||
{ "copy", no_argument, NULL, ARG_COPY },
|
||||
{ "copy-locale", no_argument, NULL, ARG_COPY_LOCALE },
|
||||
{ "copy-keymap", no_argument, NULL, ARG_COPY_KEYMAP },
|
||||
{ "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE },
|
||||
{ "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD },
|
||||
{ "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "locale", required_argument, NULL, ARG_LOCALE },
|
||||
{ "locale-messages", required_argument, NULL, ARG_LOCALE_MESSAGES },
|
||||
{ "keymap", required_argument, NULL, ARG_KEYMAP },
|
||||
{ "timezone", required_argument, NULL, ARG_TIMEZONE },
|
||||
{ "hostname", required_argument, NULL, ARG_HOSTNAME },
|
||||
{ "machine-id", required_argument, NULL, ARG_MACHINE_ID },
|
||||
{ "root-password", required_argument, NULL, ARG_ROOT_PASSWORD },
|
||||
{ "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE },
|
||||
{ "root-password-hashed", required_argument, NULL, ARG_ROOT_PASSWORD_HASHED },
|
||||
{ "kernel-command-line", required_argument, NULL, ARG_KERNEL_COMMAND_LINE },
|
||||
{ "prompt", no_argument, NULL, ARG_PROMPT },
|
||||
{ "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE },
|
||||
{ "prompt-keymap", no_argument, NULL, ARG_PROMPT_KEYMAP },
|
||||
{ "prompt-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE },
|
||||
{ "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME },
|
||||
{ "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD },
|
||||
{ "copy", no_argument, NULL, ARG_COPY },
|
||||
{ "copy-locale", no_argument, NULL, ARG_COPY_LOCALE },
|
||||
{ "copy-keymap", no_argument, NULL, ARG_COPY_KEYMAP },
|
||||
{ "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE },
|
||||
{ "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD },
|
||||
{ "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID },
|
||||
{ "force", no_argument, NULL, ARG_FORCE },
|
||||
{ "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -838,6 +993,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
r = free_and_strdup(&arg_root_password, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
arg_root_password_is_hashed = false;
|
||||
break;
|
||||
|
||||
case ARG_ROOT_PASSWORD_FILE:
|
||||
@@ -847,6 +1004,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read %s: %m", optarg);
|
||||
|
||||
arg_root_password_is_hashed = false;
|
||||
break;
|
||||
|
||||
case ARG_ROOT_PASSWORD_HASHED:
|
||||
r = free_and_strdup(&arg_root_password, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
arg_root_password_is_hashed = true;
|
||||
break;
|
||||
|
||||
case ARG_HOSTNAME:
|
||||
@@ -868,6 +1034,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_KERNEL_COMMAND_LINE:
|
||||
r = free_and_strdup(&arg_kernel_cmdline, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
break;
|
||||
|
||||
case ARG_PROMPT:
|
||||
arg_prompt_locale = arg_prompt_keymap = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = true;
|
||||
break;
|
||||
@@ -920,6 +1093,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_FORCE:
|
||||
arg_force = true;
|
||||
break;
|
||||
|
||||
case ARG_DELETE_ROOT_PASSWORD:
|
||||
arg_delete_root_password = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@@ -935,6 +1116,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_locale_messages && !locale_is_ok(arg_locale_messages))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
|
||||
|
||||
if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--delete-root-password cannot be combined with other root password options");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -980,6 +1165,10 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = process_kernel_cmdline();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+8
-30
@@ -345,28 +345,6 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sync_rights(FILE *from, const char *to) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fileno(from), &st) < 0)
|
||||
return -errno;
|
||||
|
||||
return chmod_and_chown_unsafe(to, st.st_mode & 07777, st.st_uid, st.st_gid);
|
||||
}
|
||||
|
||||
static int rename_and_apply_smack(const char *temp_path, const char *dest_path) {
|
||||
int r = 0;
|
||||
if (rename(temp_path, dest_path) < 0)
|
||||
return -errno;
|
||||
|
||||
#ifdef SMACK_RUN_LABEL
|
||||
r = mac_smack_apply(dest_path, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char* default_shell(uid_t uid) {
|
||||
return uid == 0 ? "/bin/sh" : NOLOGIN;
|
||||
}
|
||||
@@ -389,7 +367,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
|
||||
original = fopen(passwd_path, "re");
|
||||
if (original) {
|
||||
|
||||
r = sync_rights(original, passwd_tmp);
|
||||
r = sync_rights(fileno(original), fileno(passwd));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -491,7 +469,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
|
||||
original = fopen(shadow_path, "re");
|
||||
if (original) {
|
||||
|
||||
r = sync_rights(original, shadow_tmp);
|
||||
r = sync_rights(fileno(original), fileno(shadow));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -588,7 +566,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
|
||||
original = fopen(group_path, "re");
|
||||
if (original) {
|
||||
|
||||
r = sync_rights(original, group_tmp);
|
||||
r = sync_rights(fileno(original), fileno(group));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -687,7 +665,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
|
||||
if (original) {
|
||||
struct sgrp *sg;
|
||||
|
||||
r = sync_rights(original, gshadow_tmp);
|
||||
r = sync_rights(fileno(original), fileno(gshadow));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -794,14 +772,14 @@ static int write_files(void) {
|
||||
|
||||
/* And make the new files count */
|
||||
if (group) {
|
||||
r = rename_and_apply_smack(group_tmp, group_path);
|
||||
r = rename_and_apply_smack_floor_label(group_tmp, group_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
group_tmp = mfree(group_tmp);
|
||||
}
|
||||
if (gshadow) {
|
||||
r = rename_and_apply_smack(gshadow_tmp, gshadow_path);
|
||||
r = rename_and_apply_smack_floor_label(gshadow_tmp, gshadow_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -809,14 +787,14 @@ static int write_files(void) {
|
||||
}
|
||||
|
||||
if (passwd) {
|
||||
r = rename_and_apply_smack(passwd_tmp, passwd_path);
|
||||
r = rename_and_apply_smack_floor_label(passwd_tmp, passwd_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
passwd_tmp = mfree(passwd_tmp);
|
||||
}
|
||||
if (shadow) {
|
||||
r = rename_and_apply_smack(shadow_tmp, shadow_path);
|
||||
r = rename_and_apply_smack_floor_label(shadow_tmp, shadow_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user