1
0
mirror of https://github.com/systemd/systemd synced 2026-04-21 22:44:51 +02:00

Compare commits

...

2 Commits

Author SHA1 Message Date
Lennart Poettering
e99ca14741 env-util: replace unsetenv_erase() by new getenv_steal_erase() helper
The new helper combines a bunch of steps every invocation of
unsetenv_erase() did so far: getenv() + strdup() + unsetenv_erase().
Let's unify this into one helper that is harder to use incorrectly. It's
in inspired by TAKE_PTR() in a way: get the env var out and invalidate
where it was before.
2022-02-20 12:38:06 +09:00
Yu Watanabe
5cf84d2545 NEWS: fix typo 2022-02-20 11:10:44 +09:00
10 changed files with 92 additions and 86 deletions

2
NEWS
View File

@ -20,7 +20,7 @@ CHANGES WITH 251:
is mapped almost fully, with the exception of the UID subrange used is mapped almost fully, with the exception of the UID subrange used
for systemd-homed users, with one exception from that: the user's own for systemd-homed users, with one exception from that: the user's own
UID). Unmapped UIDs may not be used for file ownership in the home UID). Unmapped UIDs may not be used for file ownership in the home
dirctory — any chown() attempts with them will fail. With this directory — any chown() attempts with them will fail. With this
release a fourth range is added to these mappings: release a fourth range is added to these mappings:
524288…1879048191. This range is the UID range intended for container 524288…1879048191. This range is the UID range intended for container
uses, see: uses, see:

View File

@ -868,19 +868,36 @@ int getenv_path_list(const char *name, char ***ret_paths) {
return 1; return 1;
} }
int unsetenv_erase(const char *name) { int getenv_steal_erase(const char *name, char **ret) {
char *p; _cleanup_(erase_and_freep) char *a = NULL;
char *e;
assert(name); assert(name);
p = getenv(name); /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes
if (!p) * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for
return 0; * testing, and given that people are likely going to misuse this, be thorough) */
string_erase(p); e = getenv(name);
if (!e) {
if (ret)
*ret = NULL;
return 0;
}
if (ret) {
a = strdup(e);
if (!a)
return -ENOMEM;
}
string_erase(e);
if (unsetenv(name) < 0) if (unsetenv(name) < 0)
return -errno; return -errno;
if (ret)
*ret = TAKE_PTR(a);
return 1; return 1;
} }

View File

@ -70,3 +70,5 @@ int setenv_systemd_exec_pid(bool update_only);
int getenv_path_list(const char *name, char ***ret_paths); int getenv_path_list(const char *name, char ***ret_paths);
int unsetenv_erase(const char *name); int unsetenv_erase(const char *name);
int getenv_steal_erase(const char *name, char **ret);

View File

@ -17,20 +17,13 @@ int enroll_password(
_cleanup_free_ char *error = NULL; _cleanup_free_ char *error = NULL;
const char *node; const char *node;
int r, keyslot; int r, keyslot;
char *e;
assert_se(node = crypt_get_device_name(cd)); assert_se(node = crypt_get_device_name(cd));
e = getenv("NEWPASSWORD"); r = getenv_steal_erase("NEWPASSWORD", &new_password);
if (e) { if (r < 0)
return log_error_errno(r, "Failed to acquire password from environment: %m");
new_password = strdup(e); if (r == 0) {
if (!new_password)
return log_oom();
assert_se(unsetenv_erase("NEWPASSWORD") >= 0);
} else {
_cleanup_free_ char *disk_path = NULL; _cleanup_free_ char *disk_path = NULL;
unsigned i = 5; unsigned i = 5;
const char *id; const char *id;

View File

@ -409,8 +409,8 @@ static int prepare_luks(
size_t *ret_volume_key_size) { size_t *ret_volume_key_size) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL; _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) char *envpw = NULL;
_cleanup_(erase_and_freep) void *vk = NULL; _cleanup_(erase_and_freep) void *vk = NULL;
char *e = NULL;
size_t vks; size_t vks;
int r; int r;
@ -445,23 +445,17 @@ static int prepare_luks(
if (!vk) if (!vk)
return log_oom(); return log_oom();
e = getenv("PASSWORD"); r = getenv_steal_erase("PASSWORD", &envpw);
if (e) { if (r < 0)
_cleanup_(erase_and_freep) char *password = NULL; return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r > 0) {
password = strdup(e);
if (!password)
return log_oom();
assert_se(unsetenv_erase("PASSWORD") >= 0);
r = crypt_volume_key_get( r = crypt_volume_key_get(
cd, cd,
CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
vk, vk,
&vks, &vks,
password, envpw,
strlen(password)); strlen(envpw));
if (r < 0) if (r < 0)
return log_error_errno(r, "Password from environment variable $PASSWORD did not work."); return log_error_errno(r, "Password from environment variable $PASSWORD did not work.");
} else { } else {

View File

@ -30,12 +30,12 @@ int acquire_fido2_key(
size_t *ret_decrypted_key_size, size_t *ret_decrypted_key_size,
AskPasswordFlags ask_password_flags) { AskPasswordFlags ask_password_flags) {
_cleanup_(erase_and_freep) char *envpw = NULL;
_cleanup_strv_free_erase_ char **pins = NULL; _cleanup_strv_free_erase_ char **pins = NULL;
_cleanup_free_ void *loaded_salt = NULL; _cleanup_free_ void *loaded_salt = NULL;
bool device_exists = false; bool device_exists = false;
const char *salt; const char *salt;
size_t salt_size; size_t salt_size;
char *e;
int r; int r;
ask_password_flags |= ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; ask_password_flags |= ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
@ -66,13 +66,13 @@ int acquire_fido2_key(
salt = loaded_salt; salt = loaded_salt;
} }
e = getenv("PIN"); r = getenv_steal_erase("PIN", &envpw);
if (e) { if (r < 0)
pins = strv_new(e); return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r > 0) {
pins = strv_new(envpw);
if (!pins) if (!pins)
return log_oom(); return log_oom();
assert_se(unsetenv_erase("PIN") >= 0);
} }
for (;;) { for (;;) {

View File

@ -818,20 +818,19 @@ static bool libcryptsetup_plugins_support(void) {
#if HAVE_LIBCRYPTSETUP_PLUGINS #if HAVE_LIBCRYPTSETUP_PLUGINS
static int acquire_pins_from_env_variable(char ***ret_pins) { static int acquire_pins_from_env_variable(char ***ret_pins) {
char *e; _cleanup_(erase_and_freep) char *envpin = NULL;
_cleanup_strv_free_erase_ char **pins = NULL; _cleanup_strv_free_erase_ char **pins = NULL;
int r;
assert(ret_pins); assert(ret_pins);
e = getenv("PIN"); r = getenv_steal_erase("PIN", &envpin);
if (e) { if (r < 0)
pins = strv_new(e); return log_error_errno(r, "Failed to acquire PIN from environment: %m");
if (r > 0) {
pins = strv_new(envpin);
if (!pins) if (!pins)
return log_oom(); return log_oom();
string_erase(e);
if (unsetenv("PIN") < 0)
return log_error_errno(errno, "Failed to unset $PIN: %m");
} }
*ret_pins = TAKE_PTR(pins); *ret_pins = TAKE_PTR(pins);

View File

@ -201,24 +201,25 @@ static int acquire_existing_password(
AskPasswordFlags flags) { AskPasswordFlags flags) {
_cleanup_(strv_free_erasep) char **password = NULL; _cleanup_(strv_free_erasep) char **password = NULL;
_cleanup_(erase_and_freep) char *envpw = NULL;
_cleanup_free_ char *question = NULL; _cleanup_free_ char *question = NULL;
char *e;
int r; int r;
assert(user_name); assert(user_name);
assert(hr); assert(hr);
e = getenv("PASSWORD"); r = getenv_steal_erase("PASSWORD", &envpw);
if (e) { if (r < 0)
return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r > 0) {
/* People really shouldn't use environment variables for passing passwords. We support this /* People really shouldn't use environment variables for passing passwords. We support this
* only for testing purposes, and do not document the behaviour, so that people won't * only for testing purposes, and do not document the behaviour, so that people won't
* actually use this outside of testing. */ * actually use this outside of testing. */
r = user_record_set_password(hr, STRV_MAKE(e), true); r = user_record_set_password(hr, STRV_MAKE(envpw), true);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to store password: %m"); return log_error_errno(r, "Failed to store password: %m");
assert_se(unsetenv_erase("PASSWORD") >= 0);
return 1; return 1;
} }
@ -261,24 +262,25 @@ static int acquire_recovery_key(
AskPasswordFlags flags) { AskPasswordFlags flags) {
_cleanup_(strv_free_erasep) char **recovery_key = NULL; _cleanup_(strv_free_erasep) char **recovery_key = NULL;
_cleanup_(erase_and_freep) char *envpw = NULL;
_cleanup_free_ char *question = NULL; _cleanup_free_ char *question = NULL;
char *e;
int r; int r;
assert(user_name); assert(user_name);
assert(hr); assert(hr);
e = getenv("RECOVERY_KEY"); r = getenv_steal_erase("PASSWORD", &envpw);
if (e) { if (r < 0)
return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r > 0) {
/* People really shouldn't use environment variables for passing secrets. We support this /* People really shouldn't use environment variables for passing secrets. We support this
* only for testing purposes, and do not document the behaviour, so that people won't * only for testing purposes, and do not document the behaviour, so that people won't
* actually use this outside of testing. */ * actually use this outside of testing. */
r = user_record_set_password(hr, STRV_MAKE(e), true); /* recovery keys are stored in the record exactly like regular passwords! */ r = user_record_set_password(hr, STRV_MAKE(envpw), true); /* recovery keys are stored in the record exactly like regular passwords! */
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to store recovery key: %m"); return log_error_errno(r, "Failed to store recovery key: %m");
assert_se(unsetenv_erase("RECOVERY_KEY") >= 0);
return 1; return 1;
} }
@ -318,20 +320,21 @@ static int acquire_token_pin(
AskPasswordFlags flags) { AskPasswordFlags flags) {
_cleanup_(strv_free_erasep) char **pin = NULL; _cleanup_(strv_free_erasep) char **pin = NULL;
_cleanup_(erase_and_freep) char *envpin = NULL;
_cleanup_free_ char *question = NULL; _cleanup_free_ char *question = NULL;
char *e;
int r; int r;
assert(user_name); assert(user_name);
assert(hr); assert(hr);
e = getenv("PIN"); r = getenv_steal_erase("PIN", &envpin);
if (e) { if (r < 0)
r = user_record_set_token_pin(hr, STRV_MAKE(e), false); return log_error_errno(r, "Failed to acquire PIN from environment: %m");
if (r > 0) {
r = user_record_set_token_pin(hr, STRV_MAKE(envpin), false);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to store token PIN: %m"); return log_error_errno(r, "Failed to store token PIN: %m");
assert_se(unsetenv_erase("PIN") >= 0);
return 1; return 1;
} }
@ -1150,33 +1153,25 @@ static int acquire_new_password(
bool suggest, bool suggest,
char **ret) { char **ret) {
_cleanup_(erase_and_freep) char *envpw = NULL;
unsigned i = 5; unsigned i = 5;
char *e;
int r; int r;
assert(user_name); assert(user_name);
assert(hr); assert(hr);
e = getenv("NEWPASSWORD"); r = getenv_steal_erase("NEWPASSWORD", &envpw);
if (e) { if (r < 0)
_cleanup_(erase_and_freep) char *copy = NULL; return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r > 0) {
/* As above, this is not for use, just for testing */ /* As above, this is not for use, just for testing */
if (ret) { r = user_record_set_password(hr, STRV_MAKE(envpw), /* prepend = */ true);
copy = strdup(e);
if (!copy)
return log_oom();
}
r = user_record_set_password(hr, STRV_MAKE(e), /* prepend = */ true);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to store password: %m"); return log_error_errno(r, "Failed to store password: %m");
assert_se(unsetenv_erase("NEWPASSWORD") >= 0);
if (ret) if (ret)
*ret = TAKE_PTR(copy); *ret = TAKE_PTR(envpw);
return 0; return 0;
} }

View File

@ -275,15 +275,17 @@ int pkcs11_token_login(
for (unsigned tries = 0; tries < 3; tries++) { for (unsigned tries = 0; tries < 3; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL; _cleanup_strv_free_erase_ char **passwords = NULL;
char **i, *e; _cleanup_(erase_and_freep) char *envpin = NULL;
char **i;
e = getenv("PIN"); r = getenv_steal_erase("PIN", &envpin);
if (e) { if (r < 0)
passwords = strv_new(e); return log_error_errno(r, "Failed to acquire PIN from environment: %m");
if (r > 0) {
passwords = strv_new(envpin);
if (!passwords) if (!passwords)
return log_oom(); return log_oom();
assert_se(unsetenv_erase("PIN") >= 0);
} else if (headless) } else if (headless)
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable."); return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable.");
else { else {

View File

@ -406,17 +406,17 @@ TEST(setenv_systemd_exec_pid) {
assert_se(set_unset_env("SYSTEMD_EXEC_PID", saved, 1) >= 0); assert_se(set_unset_env("SYSTEMD_EXEC_PID", saved, 1) >= 0);
} }
TEST(unsetenv_erase) { TEST(getenv_steal_erase) {
int r; int r;
r = safe_fork("(sd-unsetenverase)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); r = safe_fork("(sd-getenvstealerase)", FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
if (r == 0) { if (r == 0) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
char **e; char **e;
/* child */ /* child */
assert_se(unsetenv_erase("thisenvvardefinitelywontexist") == 0); assert_se(getenv_steal_erase("thisenvvardefinitelywontexist", NULL) == 0);
l = strv_new("FOO=BAR", "QUUX=PIFF", "ONE=TWO", "A=B"); l = strv_new("FOO=BAR", "QUUX=PIFF", "ONE=TWO", "A=B");
assert_se(strv_length(l) == 4); assert_se(strv_length(l) == 4);
@ -424,7 +424,7 @@ TEST(unsetenv_erase) {
environ = l; environ = l;
STRV_FOREACH(e, environ) { STRV_FOREACH(e, environ) {
_cleanup_free_ char *n = NULL; _cleanup_free_ char *n = NULL, *copy1 = NULL, *copy2 = NULL;
char *eq; char *eq;
eq = strchr(*e, '='); eq = strchr(*e, '=');
@ -434,9 +434,13 @@ TEST(unsetenv_erase) {
n = strndup(*e, eq - *e); n = strndup(*e, eq - *e);
assert_se(n); assert_se(n);
assert_se(streq_ptr(getenv(n), eq + 1)); copy1 = strdup(eq + 1);
assert_se(copy1);
assert_se(streq_ptr(getenv(n), copy1));
assert_se(getenv(n) == eq + 1); assert_se(getenv(n) == eq + 1);
assert_se(unsetenv_erase(n) > 0); assert_se(getenv_steal_erase(n, &copy2) > 0);
assert_se(streq_ptr(copy1, copy2));
assert_se(isempty(eq + 1)); assert_se(isempty(eq + 1));
assert_se(!getenv(n)); assert_se(!getenv(n));
} }