summaryrefslogtreecommitdiff
path: root/src/nss-systemd/userdb-glue.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-05-05 16:11:26 +0200
committerLennart Poettering <lennart@poettering.net>2021-05-08 14:35:28 +0200
commitf43a19ecd6e3415ec223f245204b4eaaff739af4 (patch)
tree81745ffa658dd9ec54081488c7e090c65f1702a4 /src/nss-systemd/userdb-glue.c
parent09001dbdc88f447656d79822bbff9c6d7ed7e5cf (diff)
downloadsystemd-f43a19ecd6e3415ec223f245204b4eaaff739af4.tar.gz
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.
Diffstat (limited to 'src/nss-systemd/userdb-glue.c')
-rw-r--r--src/nss-systemd/userdb-glue.c151
1 files changed, 149 insertions, 2 deletions
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;
+}