diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-05-05 16:11:26 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-05-08 14:35:28 +0200 |
commit | f43a19ecd6e3415ec223f245204b4eaaff739af4 (patch) | |
tree | 81745ffa658dd9ec54081488c7e090c65f1702a4 | |
parent | nss-systemd: set USERDB_SUPPRESS_SHADOW flag when looking up user records (diff) | |
download | systemd-f43a19ecd6e3415ec223f245204b4eaaff739af4.tar.xz systemd-f43a19ecd6e3415ec223f245204b4eaaff739af4.zip |
nss-systemd: synthesize NSS shadow/gshadow records from userdb, as well
This ensures we not only synthesize regular paswd/group records of
userdb records, but shadow records as well. This should make sure that
userdb can be used as comprehensive superset of the classic
passwd/group/shadow/gshadow functionality.
-rw-r--r-- | factory/etc/nsswitch.conf | 3 | ||||
-rw-r--r-- | man/nss-myhostname.xml | 4 | ||||
-rw-r--r-- | man/nss-mymachines.xml | 3 | ||||
-rw-r--r-- | man/nss-resolve.xml | 3 | ||||
-rw-r--r-- | man/nss-systemd.xml | 9 | ||||
-rw-r--r-- | src/basic/nss-util.h | 36 | ||||
-rw-r--r-- | src/nss-systemd/nss-systemd.c | 298 | ||||
-rw-r--r-- | src/nss-systemd/nss-systemd.sym | 8 | ||||
-rw-r--r-- | src/nss-systemd/userdb-glue.c | 151 | ||||
-rw-r--r-- | src/nss-systemd/userdb-glue.h | 7 |
10 files changed, 511 insertions, 11 deletions
diff --git a/factory/etc/nsswitch.conf b/factory/etc/nsswitch.conf index d87f8811ec..acfa8474d2 100644 --- a/factory/etc/nsswitch.conf +++ b/factory/etc/nsswitch.conf @@ -2,7 +2,8 @@ passwd: compat systemd group: compat [SUCCESS=merge] systemd -shadow: compat +shadow: compat systemd +gshadow: files systemd hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns networks: files diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml index 8a603fb9ce..98eb0ec77e 100644 --- a/man/nss-myhostname.xml +++ b/man/nss-myhostname.xml @@ -91,7 +91,9 @@ <!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf --> <programlisting>passwd: compat systemd group: compat [SUCCESS=merge] systemd -shadow: compat +shadow: compat systemd +gshadow: files systemd + # Either (untrusted network, see above): hosts: mymachines resolve [!UNAVAIL=return] files <command>myhostname</command> dns diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml index b2785df410..03fcd4308e 100644 --- a/man/nss-mymachines.xml +++ b/man/nss-mymachines.xml @@ -57,7 +57,8 @@ <!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf --> <programlisting>passwd: compat systemd group: compat [SUCCESS=merge] systemd -shadow: compat +shadow: compat systemd +gshadow: files systemd hosts: <command>mymachines</command> resolve [!UNAVAIL=return] files myhostname dns networks: files diff --git a/man/nss-resolve.xml b/man/nss-resolve.xml index 78c92030ac..97c3768100 100644 --- a/man/nss-resolve.xml +++ b/man/nss-resolve.xml @@ -63,7 +63,8 @@ <!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf --> <programlisting>passwd: compat systemd group: compat [SUCCESS=merge] systemd -shadow: compat +shadow: compat systemd +gshadow: files systemd hosts: mymachines <command>resolve [!UNAVAIL=return]</command> files myhostname dns networks: files diff --git a/man/nss-systemd.xml b/man/nss-systemd.xml index 1fee8cc8ba..d42a866b0f 100644 --- a/man/nss-systemd.xml +++ b/man/nss-systemd.xml @@ -47,11 +47,13 @@ for resolving users and groups, but also works without the service running.</para> <para>To activate the NSS module, add <literal>systemd</literal> to the lines starting with - <literal>passwd:</literal> and <literal>group:</literal> in <filename>/etc/nsswitch.conf</filename>.</para> + <literal>passwd:</literal>, <literal>group:</literal>, <literal>shadow:</literal> and + <literal>gshadow:</literal> in <filename>/etc/nsswitch.conf</filename>.</para> <para>It is recommended to place <literal>systemd</literal> after the <literal>files</literal> or <literal>compat</literal> entry of the <filename>/etc/nsswitch.conf</filename> lines so that - <filename>/etc/passwd</filename> and <filename>/etc/group</filename> based mappings take precedence.</para> + <filename>/etc/passwd</filename>, <filename>/etc/group</filename>, <filename>/etc/shadow</filename> and + <filename>/etc/gshadow</filename> based mappings take precedence.</para> </refsect1> <refsect1> @@ -63,7 +65,8 @@ <!-- synchronize with other nss-* man pages and factory/etc/nsswitch.conf --> <programlisting>passwd: compat <command>systemd</command> group: compat [SUCCESS=merge] <command>systemd</command> -shadow: compat +shadow: compat <command>systemd</command> +gshadow: files <command>systemd</command> hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns networks: files diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index 3c59dcc03c..579e2c0bde 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -127,6 +127,20 @@ enum nss_status _nss_##module##_getpwuid_r( \ char *buffer, size_t buflen, \ int *errnop) _public_ +#define NSS_GETSP_PROTOTYPES(module) \ +enum nss_status _nss_##module##_getspnam_r( \ + const char *name, \ + struct spwd *spwd, \ + char *buffer, size_t buflen, \ + int *errnop) _public_ + +#define NSS_GETSG_PROTOTYPES(module) \ +enum nss_status _nss_##module##_getsgnam_r( \ + const char *name, \ + struct sgrp *sgrp, \ + char *buffer, size_t buflen, \ + int *errnop) _public_ + #define NSS_GETGR_PROTOTYPES(module) \ enum nss_status _nss_##module##_getgrnam_r( \ const char *name, \ @@ -150,6 +164,17 @@ enum nss_status _nss_##module##_getpwent_r( \ size_t buflen, \ int *errnop) _public_; +#define NSS_SPENT_PROTOTYPES(module) \ +enum nss_status _nss_##module##_endspent( \ + void) _public_; \ +enum nss_status _nss_##module##_setspent( \ + int stayopen) _public_; \ +enum nss_status _nss_##module##_getspent_r( \ + struct spwd *spwd, \ + char *buffer, \ + size_t buflen, \ + int *errnop) _public_; + #define NSS_GRENT_PROTOTYPES(module) \ enum nss_status _nss_##module##_endgrent( \ void) _public_; \ @@ -161,6 +186,17 @@ enum nss_status _nss_##module##_getgrent_r( \ size_t buflen, \ int *errnop) _public_; +#define NSS_SGENT_PROTOTYPES(module) \ +enum nss_status _nss_##module##_endsgent( \ + void) _public_; \ +enum nss_status _nss_##module##_setsgent( \ + int stayopen) _public_; \ +enum nss_status _nss_##module##_getsgent_r( \ + struct sgrp *sgrp, \ + char *buffer, \ + size_t buflen, \ + int *errnop) _public_; + #define NSS_INITGROUPS_PROTOTYPE(module) \ enum nss_status _nss_##module##_initgroups_dyn( \ const char *user, \ diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index 14712f8735..1b0866109a 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -28,6 +28,18 @@ static const struct passwd root_passwd = { .pw_shell = (char*) "/bin/sh", }; +static const struct spwd root_spwd = { + .sp_namp = (char*) "root", + .sp_pwdp = (char*) PASSWORD_LOCKED_AND_INVALID, + .sp_lstchg = -1, + .sp_min = -1, + .sp_max = -1, + .sp_warn = -1, + .sp_inact = -1, + .sp_expire = -1, + .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */ +}; + static const struct passwd nobody_passwd = { .pw_name = (char*) NOBODY_USER_NAME, .pw_passwd = (char*) PASSWORD_LOCKED_AND_INVALID, @@ -38,6 +50,18 @@ static const struct passwd nobody_passwd = { .pw_shell = (char*) NOLOGIN, }; +static const struct spwd nobody_spwd = { + .sp_namp = (char*) NOBODY_USER_NAME, + .sp_pwdp = (char*) PASSWORD_LOCKED_AND_INVALID, + .sp_lstchg = -1, + .sp_min = -1, + .sp_max = -1, + .sp_warn = -1, + .sp_inact = -1, + .sp_expire = -1, + .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */ +}; + static const struct group root_group = { .gr_name = (char*) "root", .gr_gid = 0, @@ -45,6 +69,11 @@ static const struct group root_group = { .gr_mem = (char*[]) { NULL }, }; +static const struct sgrp root_sgrp = { + .sg_namp = (char*) "root", + .sg_passwd = (char*) PASSWORD_LOCKED_AND_INVALID, +}; + static const struct group nobody_group = { .gr_name = (char*) NOBODY_GROUP_NAME, .gr_gid = GID_NOBODY, @@ -52,6 +81,11 @@ static const struct group nobody_group = { .gr_mem = (char*[]) { NULL }, }; +static const struct sgrp nobody_sgrp = { + .sg_namp = (char*) NOBODY_GROUP_NAME, + .sg_passwd = (char*) PASSWORD_LOCKED_AND_INVALID, +}; + typedef struct GetentData { /* As explained in NOTES section of getpwent_r(3) as 'getpwent_r() is not really reentrant since it * shares the reading position in the stream with all other threads', we need to protect the data in @@ -66,11 +100,19 @@ typedef struct GetentData { } GetentData; static GetentData getpwent_data = { - .mutex = PTHREAD_MUTEX_INITIALIZER + .mutex = PTHREAD_MUTEX_INITIALIZER, }; static GetentData getgrent_data = { - .mutex = PTHREAD_MUTEX_INITIALIZER + .mutex = PTHREAD_MUTEX_INITIALIZER, +}; + +static GetentData getspent_data = { + .mutex = PTHREAD_MUTEX_INITIALIZER, +}; + +static GetentData getsgent_data = { + .mutex = PTHREAD_MUTEX_INITIALIZER, }; static void setup_logging(void) { @@ -88,9 +130,13 @@ static void setup_logging_once(void) { setup_logging_once() NSS_GETPW_PROTOTYPES(systemd); +NSS_GETSP_PROTOTYPES(systemd); NSS_GETGR_PROTOTYPES(systemd); +NSS_GETSG_PROTOTYPES(systemd); NSS_PWENT_PROTOTYPES(systemd); +NSS_SPENT_PROTOTYPES(systemd); NSS_GRENT_PROTOTYPES(systemd); +NSS_SGENT_PROTOTYPES(systemd); NSS_INITGROUPS_PROTOTYPE(systemd); enum nss_status _nss_systemd_getpwnam_r( @@ -191,6 +237,54 @@ enum nss_status _nss_systemd_getpwuid_r( return status; } +enum nss_status _nss_systemd_getspnam_r( + const char *name, + struct spwd *spwd, + char *buffer, size_t buflen, + int *errnop) { + + enum nss_status status; + int e; + + PROTECT_ERRNO; + NSS_ENTRYPOINT_BEGIN; + + assert(name); + assert(spwd); + assert(errnop); + + if (!valid_user_group_name(name, VALID_USER_RELAX)) + return NSS_STATUS_NOTFOUND; + + /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */ + if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { + + if (streq(name, root_spwd.sp_namp)) { + *spwd = root_spwd; + return NSS_STATUS_SUCCESS; + } + + if (streq(name, nobody_spwd.sp_namp)) { + if (!synthesize_nobody()) + return NSS_STATUS_NOTFOUND; + + *spwd = nobody_spwd; + return NSS_STATUS_SUCCESS; + } + + } else if (STR_IN_SET(name, root_spwd.sp_namp, nobody_spwd.sp_namp)) + return NSS_STATUS_NOTFOUND; + + status = userdb_getspnam(name, spwd, buffer, buflen, &e); + if (IN_SET(status, NSS_STATUS_UNAVAIL, NSS_STATUS_TRYAGAIN)) { + UNPROTECT_ERRNO; + *errnop = e; + return status; + } + + return status; +} + #pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess" enum nss_status _nss_systemd_getgrnam_r( @@ -288,6 +382,54 @@ enum nss_status _nss_systemd_getgrgid_r( return status; } +enum nss_status _nss_systemd_getsgnam_r( + const char *name, + struct sgrp *sgrp, + char *buffer, size_t buflen, + int *errnop) { + + enum nss_status status; + int e; + + PROTECT_ERRNO; + NSS_ENTRYPOINT_BEGIN; + + assert(name); + assert(sgrp); + assert(errnop); + + if (!valid_user_group_name(name, VALID_USER_RELAX)) + return NSS_STATUS_NOTFOUND; + + /* Synthesize records for root and nobody, in case they are missing from /etc/group */ + if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) { + + if (streq(name, root_sgrp.sg_namp)) { + *sgrp = root_sgrp; + return NSS_STATUS_SUCCESS; + } + + if (streq(name, nobody_sgrp.sg_namp)) { + if (!synthesize_nobody()) + return NSS_STATUS_NOTFOUND; + + *sgrp = nobody_sgrp; + return NSS_STATUS_SUCCESS; + } + + } else if (STR_IN_SET(name, root_sgrp.sg_namp, nobody_sgrp.sg_namp)) + return NSS_STATUS_NOTFOUND; + + status = userdb_getsgnam(name, sgrp, buffer, buflen, &e); + if (IN_SET(status, NSS_STATUS_UNAVAIL, NSS_STATUS_TRYAGAIN)) { + UNPROTECT_ERRNO; + *errnop = e; + return status; + } + + return status; +} + static enum nss_status nss_systemd_endent(GetentData *p) { PROTECT_ERRNO; NSS_ENTRYPOINT_BEGIN; @@ -307,10 +449,18 @@ enum nss_status _nss_systemd_endpwent(void) { return nss_systemd_endent(&getpwent_data); } +enum nss_status _nss_systemd_endspent(void) { + return nss_systemd_endent(&getspent_data); +} + enum nss_status _nss_systemd_endgrent(void) { return nss_systemd_endent(&getgrent_data); } +enum nss_status _nss_systemd_endsgent(void) { + return nss_systemd_endent(&getsgent_data); +} + enum nss_status _nss_systemd_setpwent(int stayopen) { int r; @@ -355,6 +505,46 @@ enum nss_status _nss_systemd_setgrent(int stayopen) { return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS; } +enum nss_status _nss_systemd_setspent(int stayopen) { + int r; + + PROTECT_ERRNO; + NSS_ENTRYPOINT_BEGIN; + + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; + + _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = pthread_mutex_lock_assert(&getspent_data.mutex); + (void) _l; /* make llvm shut up about _l not being used. */ + + getspent_data.iterator = userdb_iterator_free(getspent_data.iterator); + getspent_data.by_membership = false; + + /* See _nss_systemd_setpwent() for an explanation why we use USERDB_DONT_SYNTHESIZE here */ + r = userdb_all(nss_glue_userdb_flags() | USERDB_DONT_SYNTHESIZE, &getspent_data.iterator); + return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS; +} + +enum nss_status _nss_systemd_setsgent(int stayopen) { + int r; + + PROTECT_ERRNO; + NSS_ENTRYPOINT_BEGIN; + + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; + + _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = pthread_mutex_lock_assert(&getsgent_data.mutex); + (void) _l; /* make llvm shut up about _l not being used. */ + + getsgent_data.iterator = userdb_iterator_free(getsgent_data.iterator); + getsgent_data.by_membership = false; + + /* See _nss_systemd_setpwent() for an explanation why we use USERDB_DONT_SYNTHESIZE here */ + r = groupdb_all(nss_glue_userdb_flags() | USERDB_DONT_SYNTHESIZE, &getsgent_data.iterator); + return r < 0 ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS; +} + enum nss_status _nss_systemd_getpwent_r( struct passwd *result, char *buffer, size_t buflen, @@ -527,6 +717,110 @@ enum nss_status _nss_systemd_getgrent_r( return NSS_STATUS_SUCCESS; } +enum nss_status _nss_systemd_getspent_r( + struct spwd *result, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_(user_record_unrefp) UserRecord *ur = NULL; + int r; + + PROTECT_ERRNO; + NSS_ENTRYPOINT_BEGIN; + + assert(result); + assert(errnop); + + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; + + _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = pthread_mutex_lock_assert(&getspent_data.mutex); + (void) _l; /* make llvm shut up about _l not being used. */ + + if (!getspent_data.iterator) { + UNPROTECT_ERRNO; + *errnop = EHOSTDOWN; + return NSS_STATUS_UNAVAIL; + } + + for (;;) { + r = userdb_iterator_get(getspent_data.iterator, &ur); + if (r == -ESRCH) + return NSS_STATUS_NOTFOUND; + if (r < 0) { + UNPROTECT_ERRNO; + *errnop = -r; + return NSS_STATUS_UNAVAIL; + } + + if (!ur->incomplete) /* don't synthesize shadow records for records where we couldn't read shadow data */ + break; + + ur = user_record_unref(ur); + } + + r = nss_pack_user_record_shadow(ur, result, buffer, buflen); + if (r < 0) { + UNPROTECT_ERRNO; + *errnop = -r; + return NSS_STATUS_TRYAGAIN; + } + + return NSS_STATUS_SUCCESS; +} + +enum nss_status _nss_systemd_getsgent_r( + struct sgrp *result, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; + int r; + + PROTECT_ERRNO; + NSS_ENTRYPOINT_BEGIN; + + assert(result); + assert(errnop); + + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; + + _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = pthread_mutex_lock_assert(&getsgent_data.mutex); + (void) _l; /* make llvm shut up about _l not being used. */ + + if (!getsgent_data.iterator) { + UNPROTECT_ERRNO; + *errnop = EHOSTDOWN; + return NSS_STATUS_UNAVAIL; + } + + for (;;) { + r = groupdb_iterator_get(getsgent_data.iterator, &gr); + if (r == -ESRCH) + return NSS_STATUS_NOTFOUND; + if (r < 0) { + UNPROTECT_ERRNO; + *errnop = -r; + return NSS_STATUS_UNAVAIL; + } + + if (!gr->incomplete) /* don't synthesize shadow records for records where we couldn't read shadow data */ + break; + + gr = group_record_unref(gr); + } + + r = nss_pack_group_record_shadow(gr, result, buffer, buflen); + if (r < 0) { + UNPROTECT_ERRNO; + *errnop = -r; + return NSS_STATUS_TRYAGAIN; + } + + return NSS_STATUS_SUCCESS; +} + enum nss_status _nss_systemd_initgroups_dyn( const char *user_name, gid_t gid, diff --git a/src/nss-systemd/nss-systemd.sym b/src/nss-systemd/nss-systemd.sym index 7caf217144..5602f0064c 100644 --- a/src/nss-systemd/nss-systemd.sym +++ b/src/nss-systemd/nss-systemd.sym @@ -10,15 +10,23 @@ { global: _nss_systemd_getpwnam_r; + _nss_systemd_getspnam_r; _nss_systemd_getpwuid_r; _nss_systemd_endpwent; _nss_systemd_setpwent; _nss_systemd_getpwent_r; + _nss_systemd_endspent; + _nss_systemd_setspent; + _nss_systemd_getspent_r; _nss_systemd_getgrnam_r; + _nss_systemd_getsgnam_r; _nss_systemd_getgrgid_r; _nss_systemd_endgrent; _nss_systemd_setgrent; _nss_systemd_getgrent_r; + _nss_systemd_endsgent; + _nss_systemd_setsgent; + _nss_systemd_getsgent_r; _nss_systemd_initgroups_dyn; /* These two are not used by glibc, but can be used by apps to explicitly disable nss-systemd for the calling thread. */ diff --git a/src/nss-systemd/userdb-glue.c b/src/nss-systemd/userdb-glue.c index 4b04d03c95..f7df30f906 100644 --- a/src/nss-systemd/userdb-glue.c +++ b/src/nss-systemd/userdb-glue.c @@ -32,7 +32,7 @@ int nss_pack_user_record( assert(hr); assert(pwd); - assert_se(hr->user_name); + assert(hr->user_name); required = strlen(hr->user_name) + 1; assert_se(rn = user_record_real_name(hr)); @@ -129,6 +129,85 @@ enum nss_status userdb_getpwuid( return NSS_STATUS_SUCCESS; } +int nss_pack_user_record_shadow( + UserRecord *hr, + struct spwd *spwd, + char *buffer, + size_t buflen) { + + const char *hashed; + size_t required; + + assert(hr); + assert(spwd); + + assert(hr->user_name); + required = strlen(hr->user_name) + 1; + + assert_se(hashed = strv_isempty(hr->hashed_password) ? PASSWORD_LOCKED_AND_INVALID : hr->hashed_password[0]); + required += strlen(hashed) + 1; + + if (buflen < required) + return -ERANGE; + + *spwd = (struct spwd) { + .sp_namp = buffer, + .sp_lstchg = hr->last_password_change_usec == 0 ? 1 : /* map 0 to 1, since 0 means please change pasword on next login */ + hr->last_password_change_usec == UINT64_MAX ? -1 : + (long int) (hr->last_password_change_usec / USEC_PER_DAY), + .sp_min = hr->password_change_min_usec != UINT64_MAX ? (long int) (hr->password_change_min_usec / USEC_PER_DAY) : -1, + .sp_max = hr->password_change_max_usec != UINT64_MAX ? (long int) (hr->password_change_max_usec / USEC_PER_DAY) : -1, + .sp_warn = hr->password_change_warn_usec != UINT64_MAX ? (long int) (hr->password_change_warn_usec / USEC_PER_DAY) : -1, + .sp_inact = hr->password_change_inactive_usec != UINT64_MAX ? (long int) (hr->password_change_inactive_usec / USEC_PER_DAY) : -1, + .sp_expire = hr->locked > 0 || hr->not_after_usec == 0 ? 1 : /* already expired/locked */ + hr->not_after_usec == UINT64_MAX ? -1 : + (long int) (hr->not_after_usec / USEC_PER_DAY), + .sp_flag = ULONG_MAX, + }; + + assert(buffer); + + spwd->sp_pwdp = stpcpy(spwd->sp_namp, hr->user_name) + 1; + strcpy(spwd->sp_pwdp, hashed); + + return 0; +} + +enum nss_status userdb_getspnam( + const char *name, + struct spwd *spwd, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_(user_record_unrefp) UserRecord *hr = NULL; + int r; + + assert(spwd); + assert(errnop); + + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; + + r = userdb_by_name(name, nss_glue_userdb_flags(), &hr); + if (r == -ESRCH) + return NSS_STATUS_NOTFOUND; + if (r < 0) { + *errnop = -r; + return NSS_STATUS_UNAVAIL; + } + + if (hr->incomplete) /* protected records missing? */ + return NSS_STATUS_NOTFOUND; + + r = nss_pack_user_record_shadow(hr, spwd, buffer, buflen); + if (r < 0) { + *errnop = -r; + return NSS_STATUS_TRYAGAIN; + } + + return NSS_STATUS_SUCCESS; +} + int nss_pack_group_record( GroupRecord *g, char **extra_members, @@ -142,7 +221,7 @@ int nss_pack_group_record( assert(g); assert(gr); - assert_se(g->group_name); + assert(g->group_name); required = strlen(g->group_name) + 1; STRV_FOREACH(m, g->members) { @@ -327,3 +406,71 @@ enum nss_status userdb_getgrgid( return NSS_STATUS_SUCCESS; } + +int nss_pack_group_record_shadow( + GroupRecord *hr, + struct sgrp *sgrp, + char *buffer, + size_t buflen) { + + const char *hashed; + size_t required; + + assert(hr); + assert(sgrp); + + assert(hr->group_name); + required = strlen(hr->group_name) + 1; + + assert_se(hashed = strv_isempty(hr->hashed_password) ? PASSWORD_LOCKED_AND_INVALID : hr->hashed_password[0]); + required += strlen(hashed) + 1; + + if (buflen < required) + return -ERANGE; + + *sgrp = (struct sgrp) { + .sg_namp = buffer, + }; + + assert(buffer); + + sgrp->sg_passwd = stpcpy(sgrp->sg_namp, hr->group_name) + 1; + strcpy(sgrp->sg_passwd, hashed); + + return 0; +} + +enum nss_status userdb_getsgnam( + const char *name, + struct sgrp *sgrp, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_(group_record_unrefp) GroupRecord *hr = NULL; + int r; + + assert(sgrp); + assert(errnop); + + if (_nss_systemd_is_blocked()) + return NSS_STATUS_NOTFOUND; + + r = groupdb_by_name(name, nss_glue_userdb_flags(), &hr); + if (r == -ESRCH) + return NSS_STATUS_NOTFOUND; + if (r < 0) { + *errnop = -r; + return NSS_STATUS_UNAVAIL; + } + + if (hr->incomplete) /* protected records missing? */ + return NSS_STATUS_NOTFOUND; + + r = nss_pack_group_record_shadow(hr, sgrp, buffer, buflen); + if (r < 0) { + *errnop = -r; + return NSS_STATUS_TRYAGAIN; + } + + return NSS_STATUS_SUCCESS; +} diff --git a/src/nss-systemd/userdb-glue.h b/src/nss-systemd/userdb-glue.h index cb0dcb9302..386cc88955 100644 --- a/src/nss-systemd/userdb-glue.h +++ b/src/nss-systemd/userdb-glue.h @@ -13,8 +13,15 @@ UserDBFlags nss_glue_userdb_flags(void); int nss_pack_user_record(UserRecord *hr, struct passwd *pwd, char *buffer, size_t buflen); int nss_pack_group_record(GroupRecord *g, char **extra_members, struct group *gr, char *buffer, size_t buflen); +int nss_pack_user_record_shadow(UserRecord *hr, struct spwd *spwd, char *buffer, size_t buflen); +int nss_pack_group_record_shadow(GroupRecord *hr, struct sgrp *sgrp, char *buffer,size_t buflen); + enum nss_status userdb_getpwnam(const char *name, struct passwd *pwd, char *buffer, size_t buflen, int *errnop); enum nss_status userdb_getpwuid(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, int *errnop); +enum nss_status userdb_getspnam(const char *name, struct spwd *spwd, char *buffer, size_t buflen, int *errnop); + enum nss_status userdb_getgrnam(const char *name, struct group *gr, char *buffer, size_t buflen, int *errnop); enum nss_status userdb_getgrgid(gid_t gid, struct group *gr, char *buffer, size_t buflen, int *errnop); + +enum nss_status userdb_getsgnam(const char *name, struct sgrp *sgrp, char *buffer, size_t buflen, int *errnop); |