diff options
author | Lennart Poettering <lennart@poettering.net> | 2020-08-06 17:00:07 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2020-08-07 17:36:27 +0200 |
commit | 5cd12abaa0c0f3a06c9ff2048941fbe6e8b3577e (patch) | |
tree | e6744770f048f9b04b30006dcebdf512d5a0a9fd /src/shared/user-record-nss.c | |
parent | b10fd796f56e4f16f7430cd22f59f544766d3bef (diff) | |
download | systemd-5cd12abaa0c0f3a06c9ff2048941fbe6e8b3577e.tar.gz |
user-record: deal with invalid GECOS fields gracefully
Let's fix up invalid GECOS fields both when we convert from NSS to JSON
and the other way round.
Kinda sucks we have to do that, but NSS does it when writing data to
/etc/passwd, so let's do the same.
Fixes: #16668
Diffstat (limited to 'src/shared/user-record-nss.c')
-rw-r--r-- | src/shared/user-record-nss.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/src/shared/user-record-nss.c b/src/shared/user-record-nss.c index f265a2af93..b27a12c55d 100644 --- a/src/shared/user-record-nss.c +++ b/src/shared/user-record-nss.c @@ -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) |