mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 10:13:34 +08:00
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.
This commit is contained in:
parent
09001dbdc8
commit
f43a19ecd6
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, \
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user