mirror of
https://github.com/systemd/systemd
synced 2025-11-10 12:24:45 +01:00
Compare commits
3 Commits
c1c28fe2f7
...
a8c9824d2a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8c9824d2a | ||
|
|
5cd12abaa0 | ||
|
|
b10fd796f5 |
@ -863,6 +863,37 @@ bool valid_gecos(const char *d) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char *mangle_gecos(const char *d) {
|
||||
char *mangled;
|
||||
|
||||
/* Makes sure the provided string becomes valid as a GEGOS field, by dropping bad chars. glibc's
|
||||
* putwent() only changes \n and : to spaces. We do more: replace all CC too, and remove invalid
|
||||
* UTF-8 */
|
||||
|
||||
mangled = strdup(d);
|
||||
if (!mangled)
|
||||
return NULL;
|
||||
|
||||
for (char *i = mangled; *i; i++) {
|
||||
int len;
|
||||
|
||||
if ((uint8_t) *i < (uint8_t) ' ' || *i == ':') {
|
||||
*i = ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
len = utf8_encoded_valid_unichar(i, (size_t) -1);
|
||||
if (len < 0) {
|
||||
*i = ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
i += len - 1;
|
||||
}
|
||||
|
||||
return mangled;
|
||||
}
|
||||
|
||||
bool valid_home(const char *p) {
|
||||
/* Note that this function is also called by valid_shell(), any
|
||||
* changes must account for that. */
|
||||
|
||||
@ -105,6 +105,7 @@ typedef enum ValidUserFlags {
|
||||
|
||||
bool valid_user_group_name(const char *u, ValidUserFlags flags);
|
||||
bool valid_gecos(const char *d);
|
||||
char *mangle_gecos(const char *d);
|
||||
bool valid_home(const char *p);
|
||||
|
||||
static inline bool valid_shell(const char *p) {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "libcrypt-util.h"
|
||||
#include "strv.h"
|
||||
#include "user-record-nss.h"
|
||||
#include "user-util.h"
|
||||
|
||||
#define SET_IF(field, condition, value, fallback) \
|
||||
field = (condition) ? (value) : (fallback)
|
||||
@ -34,10 +35,25 @@ int nss_passwd_to_user_record(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = free_and_strdup(&hr->real_name,
|
||||
streq_ptr(pwd->pw_gecos, hr->user_name) ? NULL : empty_to_null(pwd->pw_gecos));
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* Some bad NSS modules synthesize GECOS fields with embedded ":" or "\n" characters, which are not
|
||||
* something we can output in /etc/passwd compatible format, since these are record separators
|
||||
* there. We normally refuse that, but we need to maintain compatibility with arbitrary NSS modules,
|
||||
* hence let's do what glibc does: mangle the data to fit the format. */
|
||||
if (isempty(pwd->pw_gecos) || streq_ptr(pwd->pw_gecos, hr->user_name))
|
||||
hr->real_name = mfree(hr->real_name);
|
||||
else if (valid_gecos(pwd->pw_gecos)) {
|
||||
r = free_and_strdup(&hr->real_name, pwd->pw_gecos);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
_cleanup_free_ char *mangled = NULL;
|
||||
|
||||
mangled = mangle_gecos(pwd->pw_gecos);
|
||||
if (!mangled)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(hr->real_name, mangled);
|
||||
}
|
||||
|
||||
r = free_and_strdup(&hr->home_directory, empty_to_null(pwd->pw_dir));
|
||||
if (r < 0)
|
||||
|
||||
@ -206,7 +206,6 @@ int json_dispatch_realm(const char *name, JsonVariant *variant, JsonDispatchFlag
|
||||
static int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
|
||||
char **s = userdata;
|
||||
const char *n;
|
||||
int r;
|
||||
|
||||
if (json_variant_is_null(variant)) {
|
||||
*s = mfree(*s);
|
||||
@ -217,12 +216,20 @@ static int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispa
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
|
||||
|
||||
n = json_variant_string(variant);
|
||||
if (!valid_gecos(n))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible real name.", strna(name));
|
||||
if (valid_gecos(n)) {
|
||||
if (free_and_strdup(s, n) < 0)
|
||||
return json_log_oom(variant, flags);
|
||||
} else {
|
||||
_cleanup_free_ char *m = NULL;
|
||||
|
||||
r = free_and_strdup(s, n);
|
||||
if (r < 0)
|
||||
return json_log(variant, flags, r, "Failed to allocate string: %m");
|
||||
json_log(variant, flags|JSON_DEBUG, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible string, mangling.", strna(name));
|
||||
|
||||
m = mangle_gecos(n);
|
||||
if (!m)
|
||||
return json_log_oom(variant, flags);
|
||||
|
||||
free_and_replace(*s, m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -452,6 +452,25 @@ static void test_parse_uid_range(void) {
|
||||
assert_se(parse_uid_range(" 01", &a, &b) == -EINVAL && a == 4 && b == 5);
|
||||
}
|
||||
|
||||
static void test_mangle_gecos_one(const char *input, const char *expected) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
assert_se(p = mangle_gecos(input));
|
||||
assert_se(streq(p, expected));
|
||||
assert_se(valid_gecos(p));
|
||||
}
|
||||
|
||||
static void test_mangle_gecos(void) {
|
||||
test_mangle_gecos_one("", "");
|
||||
test_mangle_gecos_one("root", "root");
|
||||
test_mangle_gecos_one("wuff\nwuff", "wuff wuff");
|
||||
test_mangle_gecos_one("wuff:wuff", "wuff wuff");
|
||||
test_mangle_gecos_one("wuff\r\n:wuff", "wuff wuff");
|
||||
test_mangle_gecos_one("\n--wüff-wäff-wöff::", " --wüff-wäff-wöff ");
|
||||
test_mangle_gecos_one("\xc3\x28", " (");
|
||||
test_mangle_gecos_one("\xe2\x28\xa1", " ( ");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_uid_to_name_one(0, "root");
|
||||
test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME);
|
||||
@ -482,6 +501,7 @@ int main(int argc, char *argv[]) {
|
||||
test_valid_user_group_name_or_numeric_relaxed();
|
||||
test_valid_user_group_name_or_numeric();
|
||||
test_valid_gecos();
|
||||
test_mangle_gecos();
|
||||
test_valid_home();
|
||||
|
||||
test_make_salt();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user