diff --git a/src/creds/creds.c b/src/creds/creds.c index 48432f8669..ac405eb3e8 100644 --- a/src/creds/creds.c +++ b/src/creds/creds.c @@ -599,8 +599,8 @@ static int verb_encrypt(int argc, char *argv[], uintptr_t _data, void *userdata) timestamp = arg_timestamp != USEC_INFINITY ? arg_timestamp : now(CLOCK_REALTIME); - if (arg_not_after != USEC_INFINITY && arg_not_after < timestamp) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before it is valid."); + if (arg_not_after != USEC_INFINITY && arg_not_after <= timestamp) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before or when it becomes valid."); if (geteuid() != 0 && !sd_id128_equal(arg_with_key, CRED_AES256_GCM_BY_NULL)) { (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password); @@ -1257,7 +1257,7 @@ static int vl_method_encrypt(sd_varlink *link, sd_json_variant *parameters, sd_v timestamp_fresh = true; } else timestamp_fresh = timestamp_is_fresh(p.timestamp); - if (p.not_after != UINT64_MAX && p.not_after < p.timestamp) + if (p.not_after != UINT64_MAX && p.not_after <= p.timestamp) return sd_varlink_error_invalid_parameter_name(link, "notAfter"); r = settle_scope(link, &p.scope, &p.uid, &cflags, /* any_scope_after_polkit= */ NULL); diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 16a5d46629..04701429ad 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -890,7 +890,6 @@ static int action_dissect( _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(table_unrefp) Table *t = NULL; _cleanup_free_ char *bn = NULL; - uint64_t size = UINT64_MAX; int r; assert(m); @@ -1009,7 +1008,7 @@ static int action_dissect( r = sd_json_buildo( &v, SD_JSON_BUILD_PAIR_STRING("name", bn), - SD_JSON_BUILD_PAIR_CONDITION(size != UINT64_MAX, "size", SD_JSON_BUILD_INTEGER(size)), + SD_JSON_BUILD_PAIR_CONDITION(m->image_size != UINT64_MAX, "size", SD_JSON_BUILD_INTEGER(m->image_size)), SD_JSON_BUILD_PAIR_INTEGER("sectorSize", m->sector_size), SD_JSON_BUILD_PAIR_CONDITION(a >= 0, "architecture", SD_JSON_BUILD_STRING(architecture_to_string(a))), SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->image_uuid), "imageUuid", SD_JSON_BUILD_UUID(m->image_uuid)), diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index f3ea57ec92..5ebaf89764 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -998,6 +998,10 @@ static int prompt_root_shell(int rfd, sd_varlink **mute_console_link) { if (r < 0) log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m"); else { + r = find_shell(rfd, arg_root_shell); + if (r < 0) + return r; + log_debug("Acquired root shell from credential."); return 0; } diff --git a/src/id128/id128.c b/src/id128/id128.c index a4452f1cc5..5326ef1f51 100644 --- a/src/id128/id128.c +++ b/src/id128/id128.c @@ -52,6 +52,10 @@ static int verb_new(int argc, char *argv[], uintptr_t _data, void *userdata) { sd_id128_t id; int r; + if (!sd_id128_is_null(arg_app)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Verb \"new\" cannot be combined with --app-specific=."); + r = sd_id128_randomize(&id); if (r < 0) return log_error_errno(r, "Failed to generate ID: %m"); diff --git a/src/repart/repart.c b/src/repart/repart.c index 23439b0b3e..48a6352c2f 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -9493,6 +9493,11 @@ static int context_fstab(Context *context) { return 0; } + if (arg_dry_run) { + log_notice("Running in dry run mode, not generating %s", arg_generate_fstab); + return 0; + } + path = path_join(arg_copy_source, arg_generate_fstab); if (!path) return log_oom(); @@ -9625,6 +9630,11 @@ static int context_crypttab(Context *context, bool late) { return 0; } + if (arg_dry_run) { + log_notice("Running in dry run mode, not generating %s", arg_generate_crypttab); + return 0; + } + path = path_join(arg_copy_source, arg_generate_crypttab); if (!path) return log_oom(); diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index 09bbf6bca8..bbba1c3eae 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -900,8 +900,8 @@ int encrypt_credential_and_warn( if (name && !credential_name_valid(name)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid credential name: %s", name); - if (not_after != USEC_INFINITY && timestamp != USEC_INFINITY && not_after < timestamp) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before it is valid (" USEC_FMT " < " USEC_FMT ").", not_after, timestamp); + if (not_after != USEC_INFINITY && timestamp != USEC_INFINITY && not_after <= timestamp) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before or when it becomes valid (" USEC_FMT " <= " USEC_FMT ").", not_after, timestamp); if (DEBUG_LOGGING) { char buf[FORMAT_TIMESTAMP_MAX]; diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index edf2929235..2b4899df55 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -2531,6 +2531,9 @@ static int verb_check_new(int argc, char *argv[], uintptr_t _data, void *userdat r = sd_json_variant_dump(json, arg_json_format_flags, stdout, NULL); if (r < 0) return log_error_errno(r, "Failed to print JSON: %m"); + + if (!context.candidate) + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 13309e352e..184444a6f5 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -323,13 +323,24 @@ static int job_on_exit(sd_event_source *s, const siginfo_t *si, void *userdata) sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Job terminated abnormally with signal %s.", signal_to_string(si->si_status)); - } else if (si->si_status != EXIT_SUCCESS) - if (j->status_errno != 0) - sd_bus_error_set_errno(&error, j->status_errno); - else - sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, - "Job failed with exit code %i.", si->si_status); - else { + } else if (si->si_status != EXIT_SUCCESS) { + bool check_new_no_update = false; + + if (j->type == JOB_CHECK_NEW && + si->si_status == EXIT_FAILURE && + job_parse_child_output(TAKE_FD(j->stdout_fd), &json) >= 0) { + sd_json_variant *v = sd_json_variant_by_key(json, "available"); + check_new_no_update = v && sd_json_variant_is_null(v); + } + + if (!check_new_no_update) { + if (j->status_errno != 0) + sd_bus_error_set_errno(&error, j->status_errno); + else + sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, + "Job failed with exit code %i.", si->si_status); + } + } else { r = job_parse_child_output(TAKE_FD(j->stdout_fd), &json); if (r < 0) sd_bus_error_set_errnof(&error, r, "Failed to parse job worker output: %m"); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 0970b76de2..8eb1ae13c5 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -468,6 +468,35 @@ static const char* pick_shell(const Item *i) { return NOLOGIN; } +static int read_shell_credential(const Item *i, char **ret) { + _cleanup_free_ char *cn = NULL, *shell = NULL; + int r; + + assert(i); + + cn = strjoin("passwd.shell.", i->name); + if (!cn) + return -ENOMEM; + + r = read_credential(cn, (void**) &shell, /* ret_size= */ NULL); + if (r < 0) { + log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn); + if (ret) + *ret = NULL; + return 0; + } + + path_simplify(shell); + if (!valid_shell(shell)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Shell credential '%s' specifies invalid login shell '%s'.", + cn, shell); + + if (ret) + *ret = TAKE_PTR(shell); + return 0; +} + static int write_temporary_passwd( Context *c, const char *passwd_path, @@ -488,6 +517,12 @@ static int write_temporary_passwd( goto done; if (arg_dry_run) { + ORDERED_HASHMAP_FOREACH(i, c->todo_uids) { + r = read_shell_credential(i, /* ret= */ NULL); + if (r < 0) + return r; + } + log_info("Would write /etc/passwd%s", glyph(GLYPH_ELLIPSIS)); goto done; } @@ -540,7 +575,7 @@ static int write_temporary_passwd( } ORDERED_HASHMAP_FOREACH(i, c->todo_uids) { - _cleanup_free_ char *creds_shell = NULL, *cn = NULL; + _cleanup_free_ char *creds_shell = NULL; struct passwd n = { .pw_name = i->name, @@ -559,15 +594,10 @@ static int write_temporary_passwd( .pw_shell = (char*) pick_shell(i), }; - /* Try to pick up the shell for this account via the credentials logic */ - cn = strjoin("passwd.shell.", i->name); - if (!cn) - return -ENOMEM; - - r = read_credential(cn, (void**) &creds_shell, NULL); + r = read_shell_credential(i, &creds_shell); if (r < 0) - log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn); - else + return r; + if (creds_shell) n.pw_shell = creds_shell; r = putpwent_sane(&n, passwd); diff --git a/test/units/TEST-50-DISSECT.dissect.sh b/test/units/TEST-50-DISSECT.dissect.sh index 9fc15d04da..5a56da55f7 100755 --- a/test/units/TEST-50-DISSECT.dissect.sh +++ b/test/units/TEST-50-DISSECT.dissect.sh @@ -19,6 +19,7 @@ fi systemd-dissect --json=short "$MINIMAL_IMAGE.raw" | \ grep -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' >/dev/null +systemd-dissect --json=short "$MINIMAL_IMAGE.raw" | grep -F '"size":' >/dev/null systemd-dissect "$MINIMAL_IMAGE.raw" | grep -F "MARKER=1" >/dev/null # shellcheck disable=SC2153 systemd-dissect "$MINIMAL_IMAGE.raw" | grep -F -f <(sed 's/"//g' "$OS_RELEASE") >/dev/null diff --git a/test/units/TEST-54-CREDS.sh b/test/units/TEST-54-CREDS.sh index 7c2774fa10..75d1c41253 100755 --- a/test/units/TEST-54-CREDS.sh +++ b/test/units/TEST-54-CREDS.sh @@ -167,6 +167,8 @@ systemd-creds --not-after="+1d" encrypt /tmp/cred.orig /tmp/cred.enc systemd-creds decrypt /tmp/cred.enc /tmp/cred.dec diff /tmp/cred.orig /tmp/cred.dec rm -f /tmp/cred.{enc,dec} +ts="$(date -u '+%Y-%m-%d %H:%M:%S UTC')" +(! systemd-creds --with-key=null --timestamp="$ts" --not-after="$ts" encrypt /tmp/cred.orig /tmp/cred.enc) # Null-key credentials and the systemd.credentials_boot_policy= setting. # diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index d5fe4897ea..dbc5017d28 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -2873,6 +2873,35 @@ EOF losetup -d "$loop" } +testcase_generate_fstab_dry_run() { + local defs root + + defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")" + root="$(mktemp --directory "/var/test-repart.root.XXXXXXXXXX")" + # shellcheck disable=SC2064 + trap "rm -rf '$defs' '$root'" RETURN + chmod 0755 "$defs" + + echo "*** testcase for skipping generated fstab in dry-run mode ***" + + mkdir -p "$root/etc" + tee "$defs/root.conf" </dev/null else diff --git a/test/units/TEST-74-AUX-UTILS.firstboot.sh b/test/units/TEST-74-AUX-UTILS.firstboot.sh index 8c3c222c88..4fbbb18efa 100755 --- a/test/units/TEST-74-AUX-UTILS.firstboot.sh +++ b/test/units/TEST-74-AUX-UTILS.firstboot.sh @@ -352,6 +352,11 @@ grep -q "^root::" "$ROOT/etc/shadow" rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow" (! systemd-firstboot --root="$ROOT" --root-shell=/bin/nonexistentshell) +WCREDS="$(mktemp -d)" +printf '/bin/nonexistentshell' >"$WCREDS/passwd.shell.root" +(! CREDENTIALS_DIRECTORY="$WCREDS" systemd-firstboot --root="$ROOT") +[[ ! -e "$ROOT/etc/passwd" ]] +rm -rf "$WCREDS" (! systemd-firstboot --root="$ROOT" --machine-id=invalidmachineid) (! systemd-firstboot --root="$ROOT" --timezone=Foo/Bar) diff --git a/test/units/TEST-74-AUX-UTILS.id128.sh b/test/units/TEST-74-AUX-UTILS.id128.sh index 5da2323461..518642442d 100755 --- a/test/units/TEST-74-AUX-UTILS.id128.sh +++ b/test/units/TEST-74-AUX-UTILS.id128.sh @@ -36,7 +36,6 @@ systemd-id128 show root --value --json=short | jq -e '.id | type == "string"' systemd-id128 --json=short new | jq -e '.id | type == "string"' systemd-id128 new -p systemd-id128 new -u -systemd-id128 new -a 4f68bce3e8cd4db196e7fbcaf984b709 systemd-id128 machine-id assert_eq "$(systemd-id128 --json=short machine-id | jq --raw-output .id)" "$("$cred/passwd.shell.creduser" +(! env CREDENTIALS_DIRECTORY="$cred" systemd-sysusers --dry-run --root="$root" --inline 'u creduser 999 "Cred User" / -') +(! env CREDENTIALS_DIRECTORY="$cred" systemd-sysusers --root="$root" --inline 'u creduser 999 "Cred User" / -') +(! grep -F creduser "$root/etc/passwd" >/dev/null 2>&1) +rm -rf "$root" "$cred" + # Ensure that a non-responsive NSS socket doesn't make sysusers fail mount -t tmpfs tmpfs /run/systemd/userdb/ touch /run/systemd/userdb/io.systemd.DynamicUser