mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-10 05:03:06 +03:00
Implement caching of nscd
This commit is contained in:
40
ChangeLog
40
ChangeLog
@@ -1,5 +1,45 @@
|
|||||||
2011-10-07 Ulrich Drepper <drepper@gmail.com>
|
2011-10-07 Ulrich Drepper <drepper@gmail.com>
|
||||||
|
|
||||||
|
* inet/getnetgrent_r.c: Hook up nscd.
|
||||||
|
* nscd/Makefile (routines): Add nscd_netgroup.
|
||||||
|
(nscd-modules): Add netgroupcache.
|
||||||
|
(CFLAGS-netgroupcache.c): Define.
|
||||||
|
* nscd/cache.c (readdfcts): Add entries for GETNETGRENT and INNETGR.
|
||||||
|
(cache_search): Add const to second parameter.
|
||||||
|
* nscd/connections.c (serv2str): Add entries for GETNETGRENT and
|
||||||
|
INNETGR.
|
||||||
|
(dbs): Add netgrdb entry.
|
||||||
|
(reqinfo): Add entries for GETNETGRENT, INNETGR, and GETFDNETGR.
|
||||||
|
(verify_persistent_db): Handle netgrdb.
|
||||||
|
(handle_request): Handle GETNETGRENT, INNETGR, and GETFDNETGR.
|
||||||
|
* nscd/nscd-client.h (request_type): Add GETNETGRENT, INNETGR, and
|
||||||
|
GETFDNETGR.
|
||||||
|
(netgroup_response_header): Define.
|
||||||
|
(innetgroup_response_header): Define.
|
||||||
|
(datahead): Add netgroup_response_header and innetgroup_response_header
|
||||||
|
elements.
|
||||||
|
* nscd/nscd.conf: Add entries for netgroup cache.
|
||||||
|
* nscd/nscd.h (dbtype): Add netgrdb.
|
||||||
|
(_PATH_NSCD_NETGROUP_DB): Define.
|
||||||
|
(netgroup_iov_disabled): Declare.
|
||||||
|
(xmalloc, xcalloc, xrealloc): Move declarations here.
|
||||||
|
(cache_search): Adjust prototype.
|
||||||
|
Add netgroup-related prototypes.
|
||||||
|
* nscd/nscd_conf.c (dbnames): Add netgrdb entry.
|
||||||
|
* nscd/nscd_proto.h (__nss_not_use_nscd_netgroup): Declare.
|
||||||
|
(__nscd_innetgr): Declare.
|
||||||
|
* nscd/selinux.c (perms): Use access_vector_t as element type and
|
||||||
|
add netgroup-related initializers.
|
||||||
|
* nscd/netgroupcache.c: New file.
|
||||||
|
* nscd/nscd_netgroup.c: New file.
|
||||||
|
* nss/Versions [libc] (GLIBC_PRIVATE): Export __nss_lookup.
|
||||||
|
* nss/getent.c (netgroup_keys): Use setnetgrent only for one parameter.
|
||||||
|
For four parameters use innetgr.
|
||||||
|
* nss/nss_files/files-init.c: Add definition and callback for netgr.
|
||||||
|
* nss/nsswitch.c (__nss_lookup): Add libc_hidden_def.
|
||||||
|
(__nss_disable_nscd): Set __nss_not_use_nscd_netgroup.
|
||||||
|
* nss/nsswitch.h (__nss_lookup): Add libc_hidden_proto.
|
||||||
|
|
||||||
* nscd/connections.c (register_traced_file): Don't register file
|
* nscd/connections.c (register_traced_file): Don't register file
|
||||||
for disabled databases.
|
for disabled databases.
|
||||||
|
|
||||||
|
5
NEWS
5
NEWS
@@ -1,4 +1,4 @@
|
|||||||
GNU C Library NEWS -- history of user-visible changes. 2011-9-11
|
GNU C Library NEWS -- history of user-visible changes. 2011-10-7
|
||||||
Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
|
Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
|
||||||
See the end for copying conditions.
|
See the end for copying conditions.
|
||||||
|
|
||||||
@@ -38,6 +38,9 @@ Version 2.15
|
|||||||
|
|
||||||
* Checking versions of FD_SET, FD_CLR, and FD_ISSET added.
|
* Checking versions of FD_SET, FD_CLR, and FD_ISSET added.
|
||||||
Implemented by Ulrich Drepper.
|
Implemented by Ulrich Drepper.
|
||||||
|
|
||||||
|
* nscd now also caches the netgroup database.
|
||||||
|
Implemented by Ulrich Drepper.
|
||||||
|
|
||||||
Version 2.14
|
Version 2.14
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "netgroup.h"
|
#include "netgroup.h"
|
||||||
#include "nsswitch.h"
|
#include "nsswitch.h"
|
||||||
#include <sysdep.h>
|
#include <sysdep.h>
|
||||||
|
#include <nscd/nscd_proto.h>
|
||||||
|
|
||||||
|
|
||||||
/* Protect above variable against multiple uses at the same time. */
|
/* Protect above variable against multiple uses at the same time. */
|
||||||
@@ -101,7 +102,7 @@ endnetgrent_hook (struct __netgrent *datap)
|
|||||||
{
|
{
|
||||||
enum nss_status (*endfct) (struct __netgrent *);
|
enum nss_status (*endfct) (struct __netgrent *);
|
||||||
|
|
||||||
if (datap->nip == NULL)
|
if (datap->nip == NULL || datap->nip == (service_user *) -1l)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
endfct = __nss_lookup_function (datap->nip, "endnetgrent");
|
endfct = __nss_lookup_function (datap->nip, "endnetgrent");
|
||||||
@@ -189,8 +190,21 @@ setnetgrent (const char *group)
|
|||||||
|
|
||||||
__libc_lock_lock (lock);
|
__libc_lock_lock (lock);
|
||||||
|
|
||||||
|
if (__nss_not_use_nscd_netgroup > 0
|
||||||
|
&& ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
|
||||||
|
__nss_not_use_nscd_netgroup = 0;
|
||||||
|
|
||||||
|
if (!__nss_not_use_nscd_netgroup
|
||||||
|
&& !__nss_database_custom[NSS_DBSIDX_netgroup])
|
||||||
|
{
|
||||||
|
result = __nscd_setnetgrent (group, &dataset);
|
||||||
|
if (result >= 0)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
result = internal_setnetgrent (group, &dataset);
|
result = internal_setnetgrent (group, &dataset);
|
||||||
|
|
||||||
|
out:
|
||||||
__libc_lock_unlock (lock);
|
__libc_lock_unlock (lock);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -226,6 +240,26 @@ int internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
|
|||||||
char *buffer, size_t buflen, int *errnop);
|
char *buffer, size_t buflen, int *errnop);
|
||||||
libc_hidden_proto (internal_getnetgrent_r)
|
libc_hidden_proto (internal_getnetgrent_r)
|
||||||
|
|
||||||
|
|
||||||
|
static enum nss_status
|
||||||
|
nscd_getnetgrent (struct __netgrent *datap, char *buffer, size_t buflen,
|
||||||
|
int *errnop)
|
||||||
|
{
|
||||||
|
if (datap->cursor >= datap->data + datap->data_size)
|
||||||
|
return NSS_STATUS_UNAVAIL;
|
||||||
|
|
||||||
|
datap->type = triple_val;
|
||||||
|
datap->val.triple.host = datap->cursor;
|
||||||
|
datap->cursor = (char *) rawmemchr (datap->cursor, '\0') + 1;
|
||||||
|
datap->val.triple.user = datap->cursor;
|
||||||
|
datap->cursor = (char *) rawmemchr (datap->cursor, '\0') + 1;
|
||||||
|
datap->val.triple.domain = datap->cursor;
|
||||||
|
datap->cursor = (char *) rawmemchr (datap->cursor, '\0') + 1;
|
||||||
|
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
|
internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
|
||||||
struct __netgrent *datap,
|
struct __netgrent *datap,
|
||||||
@@ -239,9 +273,18 @@ internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
|
|||||||
/* Run through available functions, starting with the same function last
|
/* Run through available functions, starting with the same function last
|
||||||
run. We will repeat each function as long as it succeeds, and then go
|
run. We will repeat each function as long as it succeeds, and then go
|
||||||
on to the next service action. */
|
on to the next service action. */
|
||||||
int no_more = (datap->nip == NULL
|
int no_more = datap->nip == NULL;
|
||||||
|| (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
|
if (! no_more)
|
||||||
== NULL);
|
{
|
||||||
|
if (datap->nip == (service_user *) -1l)
|
||||||
|
fct = nscd_getnetgrent;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
|
||||||
|
no_more = fct == NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (! no_more)
|
while (! no_more)
|
||||||
{
|
{
|
||||||
status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno));
|
status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno));
|
||||||
@@ -342,6 +385,18 @@ int
|
|||||||
innetgr (const char *netgroup, const char *host, const char *user,
|
innetgr (const char *netgroup, const char *host, const char *user,
|
||||||
const char *domain)
|
const char *domain)
|
||||||
{
|
{
|
||||||
|
if (__nss_not_use_nscd_netgroup > 0
|
||||||
|
&& ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
|
||||||
|
__nss_not_use_nscd_netgroup = 0;
|
||||||
|
|
||||||
|
if (!__nss_not_use_nscd_netgroup
|
||||||
|
&& !__nss_database_custom[NSS_DBSIDX_netgroup])
|
||||||
|
{
|
||||||
|
int result = __nscd_innetgr (netgroup, host, user, domain);
|
||||||
|
if (result >= 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
enum nss_status (*f) (const char *, struct __netgrent *);
|
enum nss_status (*f) (const char *, struct __netgrent *);
|
||||||
@@ -453,7 +508,7 @@ innetgr (const char *netgroup, const char *host, const char *user,
|
|||||||
entry.needed_groups = tmp->next;
|
entry.needed_groups = tmp->next;
|
||||||
tmp->next = entry.known_groups;
|
tmp->next = entry.known_groups;
|
||||||
entry.known_groups = tmp;
|
entry.known_groups = tmp;
|
||||||
current_group = entry.known_groups->name;
|
current_group = tmp->name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
subdir := nscd
|
subdir := nscd
|
||||||
|
|
||||||
routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
|
routines := nscd_getpw_r nscd_getgr_r nscd_gethst_r nscd_getai \
|
||||||
nscd_initgroups nscd_getserv_r
|
nscd_initgroups nscd_getserv_r nscd_netgroup
|
||||||
aux := nscd_helper
|
aux := nscd_helper
|
||||||
|
|
||||||
include ../Makeconfig
|
include ../Makeconfig
|
||||||
@@ -34,7 +34,8 @@ nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \
|
|||||||
getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
|
getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm3_r \
|
||||||
getsrvbynm_r getsrvbypt_r servicescache \
|
getsrvbynm_r getsrvbypt_r servicescache \
|
||||||
dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
|
dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
|
||||||
xmalloc xstrdup aicache initgrcache gai res_hconf
|
xmalloc xstrdup aicache initgrcache gai res_hconf \
|
||||||
|
netgroupcache
|
||||||
|
|
||||||
ifeq ($(have-thread-library),yes)
|
ifeq ($(have-thread-library),yes)
|
||||||
|
|
||||||
@@ -121,6 +122,7 @@ CFLAGS-servicescache.c += $(nscd-cflags)
|
|||||||
CFLAGS-getsrvbynm_r.c += $(nscd-cflags)
|
CFLAGS-getsrvbynm_r.c += $(nscd-cflags)
|
||||||
CFLAGS-getsrvbypt_r.c += $(nscd-cflags)
|
CFLAGS-getsrvbypt_r.c += $(nscd-cflags)
|
||||||
CFLAGS-res_hconf.c += $(nscd-cflags)
|
CFLAGS-res_hconf.c += $(nscd-cflags)
|
||||||
|
CFLAGS-netgroupcache.c += $(nscd-cflags)
|
||||||
|
|
||||||
ifeq (yesyes,$(have-fpie)$(build-shared))
|
ifeq (yesyes,$(have-fpie)$(build-shared))
|
||||||
LDFLAGS-nscd = -Wl,-z,now
|
LDFLAGS-nscd = -Wl,-z,now
|
||||||
|
@@ -60,7 +60,9 @@ static time_t (*const readdfcts[LASTREQ]) (struct database_dyn *,
|
|||||||
[GETAI] = readdhstai,
|
[GETAI] = readdhstai,
|
||||||
[INITGROUPS] = readdinitgroups,
|
[INITGROUPS] = readdinitgroups,
|
||||||
[GETSERVBYNAME] = readdservbyname,
|
[GETSERVBYNAME] = readdservbyname,
|
||||||
[GETSERVBYPORT] = readdservbyport
|
[GETSERVBYPORT] = readdservbyport,
|
||||||
|
[GETNETGRENT] = readdgetnetgrent,
|
||||||
|
[INNETGR] = readdinnetgr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -70,7 +72,7 @@ static time_t (*const readdfcts[LASTREQ]) (struct database_dyn *,
|
|||||||
|
|
||||||
This function must be called with the read-lock held. */
|
This function must be called with the read-lock held. */
|
||||||
struct datahead *
|
struct datahead *
|
||||||
cache_search (request_type type, void *key, size_t len,
|
cache_search (request_type type, const void *key, size_t len,
|
||||||
struct database_dyn *table, uid_t owner)
|
struct database_dyn *table, uid_t owner)
|
||||||
{
|
{
|
||||||
unsigned long int hash = __nis_hash (key, len) % table->head->module;
|
unsigned long int hash = __nis_hash (key, len) % table->head->module;
|
||||||
|
@@ -57,11 +57,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper functions with error checking for standard functions. */
|
|
||||||
extern void *xmalloc (size_t n);
|
|
||||||
extern void *xcalloc (size_t n, size_t s);
|
|
||||||
extern void *xrealloc (void *o, size_t n);
|
|
||||||
|
|
||||||
/* Support to run nscd as an unprivileged user */
|
/* Support to run nscd as an unprivileged user */
|
||||||
const char *server_user;
|
const char *server_user;
|
||||||
static uid_t server_uid;
|
static uid_t server_uid;
|
||||||
@@ -100,7 +95,10 @@ const char *const serv2str[LASTREQ] =
|
|||||||
[INITGROUPS] = "INITGROUPS",
|
[INITGROUPS] = "INITGROUPS",
|
||||||
[GETSERVBYNAME] = "GETSERVBYNAME",
|
[GETSERVBYNAME] = "GETSERVBYNAME",
|
||||||
[GETSERVBYPORT] = "GETSERVBYPORT",
|
[GETSERVBYPORT] = "GETSERVBYPORT",
|
||||||
[GETFDSERV] = "GETFDSERV"
|
[GETFDSERV] = "GETFDSERV",
|
||||||
|
[GETNETGRENT] = "GETNETGRENT",
|
||||||
|
[INNETGR] = "INNETGR",
|
||||||
|
[GETFDNETGR] = "GETFDNETGR"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The control data structures for the services. */
|
/* The control data structures for the services. */
|
||||||
@@ -181,6 +179,25 @@ struct database_dyn dbs[lastdb] =
|
|||||||
.wr_fd = -1,
|
.wr_fd = -1,
|
||||||
.ro_fd = -1,
|
.ro_fd = -1,
|
||||||
.mmap_used = false
|
.mmap_used = false
|
||||||
|
},
|
||||||
|
[netgrdb] = {
|
||||||
|
.lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
|
||||||
|
.prune_lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
.prune_run_lock = PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
.enabled = 0,
|
||||||
|
.check_file = 1,
|
||||||
|
.persistent = 0,
|
||||||
|
.propagate = 0, /* Not used. */
|
||||||
|
.shared = 0,
|
||||||
|
.max_db_size = DEFAULT_MAX_DB_SIZE,
|
||||||
|
.suggested_module = DEFAULT_SUGGESTED_MODULE,
|
||||||
|
.db_filename = _PATH_NSCD_NETGROUP_DB,
|
||||||
|
.disabled_iov = &netgroup_iov_disabled,
|
||||||
|
.postimeout = 28800,
|
||||||
|
.negtimeout = 20,
|
||||||
|
.wr_fd = -1,
|
||||||
|
.ro_fd = -1,
|
||||||
|
.mmap_used = false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -210,7 +227,10 @@ static struct
|
|||||||
[INITGROUPS] = { true, &dbs[grpdb] },
|
[INITGROUPS] = { true, &dbs[grpdb] },
|
||||||
[GETSERVBYNAME] = { true, &dbs[servdb] },
|
[GETSERVBYNAME] = { true, &dbs[servdb] },
|
||||||
[GETSERVBYPORT] = { true, &dbs[servdb] },
|
[GETSERVBYPORT] = { true, &dbs[servdb] },
|
||||||
[GETFDSERV] = { false, &dbs[servdb] }
|
[GETFDSERV] = { false, &dbs[servdb] },
|
||||||
|
[GETNETGRENT] = { true, &dbs[netgrdb] },
|
||||||
|
[INNETGR] = { true, &dbs[netgrdb] },
|
||||||
|
[GETFDNETGR] = { false, &dbs[netgrdb] }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -355,7 +375,8 @@ check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
|
|||||||
static int
|
static int
|
||||||
verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
|
verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
|
||||||
{
|
{
|
||||||
assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb);
|
assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb || dbnr == servdb
|
||||||
|
|| dbnr == netgrdb);
|
||||||
|
|
||||||
time_t now = time (NULL);
|
time_t now = time (NULL);
|
||||||
|
|
||||||
@@ -1230,6 +1251,14 @@ request from '%s' [%ld] not handled due to missing permission"),
|
|||||||
addservbyport (db, fd, req, key, uid);
|
addservbyport (db, fd, req, key, uid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GETNETGRENT:
|
||||||
|
addgetnetgrent (db, fd, req, key, uid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INNETGR:
|
||||||
|
addinnetgr (db, fd, req, key, uid);
|
||||||
|
break;
|
||||||
|
|
||||||
case GETSTAT:
|
case GETSTAT:
|
||||||
case SHUTDOWN:
|
case SHUTDOWN:
|
||||||
case INVALIDATE:
|
case INVALIDATE:
|
||||||
@@ -1276,6 +1305,7 @@ request from '%s' [%ld] not handled due to missing permission"),
|
|||||||
case GETFDGR:
|
case GETFDGR:
|
||||||
case GETFDHST:
|
case GETFDHST:
|
||||||
case GETFDSERV:
|
case GETFDSERV:
|
||||||
|
case GETFDNETGR:
|
||||||
#ifdef SCM_RIGHTS
|
#ifdef SCM_RIGHTS
|
||||||
send_ro_fd (reqinfo[req->type].db, key, fd);
|
send_ro_fd (reqinfo[req->type].db, key, fd);
|
||||||
#endif
|
#endif
|
||||||
|
669
nscd/netgroupcache.c
Normal file
669
nscd/netgroupcache.c
Normal file
@@ -0,0 +1,669 @@
|
|||||||
|
/* Cache handling for netgroup lookup.
|
||||||
|
Copyright (C) 2011 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published
|
||||||
|
by the Free Software Foundation; version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software Foundation,
|
||||||
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libintl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "../inet/netgroup.h"
|
||||||
|
#include "nscd.h"
|
||||||
|
#include "dbg_log.h"
|
||||||
|
#ifdef HAVE_SENDFILE
|
||||||
|
# include <kernel-features.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* This is the standard reply in case the service is disabled. */
|
||||||
|
static const netgroup_response_header disabled =
|
||||||
|
{
|
||||||
|
.version = NSCD_VERSION,
|
||||||
|
.found = -1,
|
||||||
|
.nresults = 0,
|
||||||
|
.result_len = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is the struct describing how to write this record. */
|
||||||
|
const struct iovec netgroup_iov_disabled =
|
||||||
|
{
|
||||||
|
.iov_base = (void *) &disabled,
|
||||||
|
.iov_len = sizeof (disabled)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* This is the standard reply in case we haven't found the dataset. */
|
||||||
|
static const netgroup_response_header notfound =
|
||||||
|
{
|
||||||
|
.version = NSCD_VERSION,
|
||||||
|
.found = 0,
|
||||||
|
.nresults = 0,
|
||||||
|
.result_len = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct dataset
|
||||||
|
{
|
||||||
|
struct datahead head;
|
||||||
|
netgroup_response_header resp;
|
||||||
|
char strdata[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static time_t
|
||||||
|
addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
|
||||||
|
const char *key, uid_t uid, struct hashentry *he,
|
||||||
|
struct datahead *dh, struct dataset **resultp)
|
||||||
|
{
|
||||||
|
if (__builtin_expect (debug_level > 0, 0))
|
||||||
|
{
|
||||||
|
if (he == NULL)
|
||||||
|
dbg_log (_("Haven't found \"%s\" in netgroup cache!"), key);
|
||||||
|
else
|
||||||
|
dbg_log (_("Reloading \"%s\" in netgroup cache!"), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static service_user *netgroup_database;
|
||||||
|
time_t timeout;
|
||||||
|
struct dataset *dataset;
|
||||||
|
bool cacheable = false;
|
||||||
|
ssize_t total;
|
||||||
|
|
||||||
|
char *key_copy = NULL;
|
||||||
|
struct __netgrent data;
|
||||||
|
size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len);
|
||||||
|
size_t buffilled = sizeof (*dataset);
|
||||||
|
char *buffer = NULL;
|
||||||
|
size_t nentries = 0;
|
||||||
|
bool use_malloc = false;
|
||||||
|
size_t group_len = strlen (key) + 1;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct name_list elem;
|
||||||
|
char mem[sizeof (struct name_list) + group_len];
|
||||||
|
} first_needed;
|
||||||
|
|
||||||
|
if (netgroup_database == NULL
|
||||||
|
&& __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
|
||||||
|
{
|
||||||
|
/* No such service. */
|
||||||
|
total = sizeof (notfound);
|
||||||
|
timeout = time (NULL) + db->negtimeout;
|
||||||
|
|
||||||
|
if (fd != -1)
|
||||||
|
TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL));
|
||||||
|
|
||||||
|
dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1);
|
||||||
|
/* If we cannot permanently store the result, so be it. */
|
||||||
|
if (dataset != NULL)
|
||||||
|
{
|
||||||
|
dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
|
||||||
|
dataset->head.recsize = total;
|
||||||
|
dataset->head.notfound = true;
|
||||||
|
dataset->head.nreloads = 0;
|
||||||
|
dataset->head.usable = true;
|
||||||
|
|
||||||
|
/* Compute the timeout time. */
|
||||||
|
timeout = dataset->head.timeout = time (NULL) + db->negtimeout;
|
||||||
|
dataset->head.ttl = db->negtimeout;
|
||||||
|
|
||||||
|
/* This is the reply. */
|
||||||
|
memcpy (&dataset->resp, ¬found, total);
|
||||||
|
|
||||||
|
/* Copy the key data. */
|
||||||
|
memcpy (dataset->strdata, key, req->key_len);
|
||||||
|
|
||||||
|
cacheable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto writeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (&data, '\0', sizeof (data));
|
||||||
|
buffer = alloca (buflen);
|
||||||
|
first_needed.elem.next = &first_needed.elem;
|
||||||
|
memcpy (first_needed.elem.name, key, group_len);
|
||||||
|
data.needed_groups = &first_needed.elem;
|
||||||
|
|
||||||
|
while (data.needed_groups != NULL)
|
||||||
|
{
|
||||||
|
/* Add the next group to the list of those which are known. */
|
||||||
|
struct name_list *this_group = data.needed_groups->next;
|
||||||
|
if (this_group == data.needed_groups)
|
||||||
|
data.needed_groups = NULL;
|
||||||
|
else
|
||||||
|
data.needed_groups->next = this_group->next;
|
||||||
|
this_group->next = data.known_groups;
|
||||||
|
data.known_groups = this_group;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
enum nss_status (*f) (const char *, struct __netgrent *);
|
||||||
|
void *ptr;
|
||||||
|
} setfct;
|
||||||
|
|
||||||
|
service_user *nip = netgroup_database;
|
||||||
|
int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr);
|
||||||
|
while (!no_more)
|
||||||
|
{
|
||||||
|
enum nss_status status
|
||||||
|
= DL_CALL_FCT (*setfct.f, (data.known_groups->name, &data));
|
||||||
|
|
||||||
|
if (status == NSS_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
enum nss_status (*f) (struct __netgrent *, char *, size_t,
|
||||||
|
int *);
|
||||||
|
void *ptr;
|
||||||
|
} getfct;
|
||||||
|
getfct.ptr = __nss_lookup_function (nip, "getnetgrent_r");
|
||||||
|
if (getfct.f != NULL)
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int e;
|
||||||
|
status = getfct.f (&data, buffer + buffilled,
|
||||||
|
buflen - buffilled, &e);
|
||||||
|
if (status == NSS_STATUS_RETURN)
|
||||||
|
/* This was the last one for this group. Look
|
||||||
|
at next group if available. */
|
||||||
|
break;
|
||||||
|
if (status == NSS_STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
if (data.type == triple_val)
|
||||||
|
{
|
||||||
|
const char *nhost = data.val.triple.host;
|
||||||
|
const char *nuser = data.val.triple.user;
|
||||||
|
const char *ndomain = data.val.triple.domain;
|
||||||
|
|
||||||
|
if (data.val.triple.host > data.val.triple.user
|
||||||
|
|| data.val.triple.user > data.val.triple.domain)
|
||||||
|
{
|
||||||
|
const char *last = MAX (nhost,
|
||||||
|
MAX (nuser, ndomain));
|
||||||
|
size_t bufused = (last + strlen (last) + 1
|
||||||
|
- buffer);
|
||||||
|
|
||||||
|
/* We have to make temporary copies. */
|
||||||
|
size_t hostlen = strlen (nhost) + 1;
|
||||||
|
size_t userlen = strlen (nuser) + 1;
|
||||||
|
size_t domainlen = strlen (ndomain) + 1;
|
||||||
|
size_t needed = hostlen + userlen + domainlen;
|
||||||
|
|
||||||
|
if (buflen - req->key_len - bufused < needed)
|
||||||
|
{
|
||||||
|
size_t newsize = MAX (2 * buflen,
|
||||||
|
buflen + 2 * needed);
|
||||||
|
if (use_malloc || newsize > 1024 * 1024)
|
||||||
|
{
|
||||||
|
buflen = newsize;
|
||||||
|
char *newbuf = xrealloc (use_malloc
|
||||||
|
? buffer
|
||||||
|
: NULL,
|
||||||
|
buflen);
|
||||||
|
|
||||||
|
buffer = newbuf;
|
||||||
|
use_malloc = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
extend_alloca (buffer, buflen, newsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
nhost = memcpy (buffer + bufused,
|
||||||
|
nhost, hostlen);
|
||||||
|
nuser = memcpy ((char *) nhost + hostlen,
|
||||||
|
nuser, userlen);
|
||||||
|
ndomain = memcpy ((char *) nuser + userlen,
|
||||||
|
ndomain, domainlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *wp = buffer + buffilled;
|
||||||
|
wp = stpcpy (wp, nhost) + 1;
|
||||||
|
wp = stpcpy (wp, nuser) + 1;
|
||||||
|
wp = stpcpy (wp, ndomain) + 1;
|
||||||
|
buffilled = wp - buffer;
|
||||||
|
++nentries;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check that the group has not been
|
||||||
|
requested before. */
|
||||||
|
struct name_list *runp = data.needed_groups;
|
||||||
|
if (runp != NULL)
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (strcmp (runp->name, data.val.group) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
runp = runp->next;
|
||||||
|
if (runp == data.needed_groups)
|
||||||
|
{
|
||||||
|
runp = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runp == NULL)
|
||||||
|
{
|
||||||
|
runp = data.known_groups;
|
||||||
|
while (runp != NULL)
|
||||||
|
if (strcmp (runp->name, data.val.group) == 0)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
runp = runp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runp == NULL)
|
||||||
|
{
|
||||||
|
/* A new group is requested. */
|
||||||
|
size_t namelen = strlen (data.val.group) + 1;
|
||||||
|
struct name_list *newg = alloca (sizeof (*newg)
|
||||||
|
+ namelen);
|
||||||
|
memcpy (newg->name, data.val.group, namelen);
|
||||||
|
if (data.needed_groups == NULL)
|
||||||
|
data.needed_groups = newg->next = newg;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newg->next = data.needed_groups->next;
|
||||||
|
data.needed_groups->next = newg;
|
||||||
|
data.needed_groups = newg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (status == NSS_STATUS_UNAVAIL && e == ERANGE)
|
||||||
|
{
|
||||||
|
size_t newsize = 2 * buflen;
|
||||||
|
if (use_malloc || newsize > 1024 * 1024)
|
||||||
|
{
|
||||||
|
buflen = newsize;
|
||||||
|
char *newbuf = xrealloc (use_malloc
|
||||||
|
? buffer : NULL, buflen);
|
||||||
|
|
||||||
|
buffer = newbuf;
|
||||||
|
use_malloc = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
extend_alloca (buffer, buflen, newsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum nss_status (*endfct) (struct __netgrent *);
|
||||||
|
endfct = __nss_lookup_function (nip, "endnetgrent");
|
||||||
|
if (endfct != NULL)
|
||||||
|
(void) DL_CALL_FCT (*endfct, (&data));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
no_more = __nss_next2 (&nip, "setnetgrent", NULL, &setfct.ptr,
|
||||||
|
status, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total = buffilled;
|
||||||
|
|
||||||
|
/* Fill in the dataset. */
|
||||||
|
dataset = (struct dataset *) buffer;
|
||||||
|
dataset->head.allocsize = total + req->key_len;
|
||||||
|
dataset->head.recsize = total - offsetof (struct dataset, resp);
|
||||||
|
dataset->head.notfound = false;
|
||||||
|
dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
|
||||||
|
dataset->head.usable = true;
|
||||||
|
dataset->head.ttl = db->postimeout;
|
||||||
|
timeout = dataset->head.timeout = time (NULL) + dataset->head.ttl;
|
||||||
|
|
||||||
|
dataset->resp.version = NSCD_VERSION;
|
||||||
|
dataset->resp.found = 1;
|
||||||
|
dataset->resp.nresults = nentries;
|
||||||
|
dataset->resp.result_len = buffilled - sizeof (*dataset);
|
||||||
|
|
||||||
|
assert (buflen - buffilled >= req->key_len);
|
||||||
|
key_copy = memcpy (buffer + buffilled, key, req->key_len);
|
||||||
|
buffilled += req->key_len;
|
||||||
|
|
||||||
|
/* Now we can determine whether on refill we have to create a new
|
||||||
|
record or not. */
|
||||||
|
if (he != NULL)
|
||||||
|
{
|
||||||
|
assert (fd == -1);
|
||||||
|
|
||||||
|
if (dataset->head.allocsize == dh->allocsize
|
||||||
|
&& dataset->head.recsize == dh->recsize
|
||||||
|
&& memcmp (&dataset->resp, dh->data,
|
||||||
|
dh->allocsize - offsetof (struct dataset, resp)) == 0)
|
||||||
|
{
|
||||||
|
/* The data has not changed. We will just bump the timeout
|
||||||
|
value. Note that the new record has been allocated on
|
||||||
|
the stack and need not be freed. */
|
||||||
|
dh->timeout = dataset->head.timeout;
|
||||||
|
dh->ttl = dataset->head.ttl;
|
||||||
|
++dh->nreloads;
|
||||||
|
dataset = (struct dataset *) dh;
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct dataset *newp
|
||||||
|
= (struct dataset *) mempool_alloc (db, total + req->key_len, 1);
|
||||||
|
if (__builtin_expect (newp != NULL, 1))
|
||||||
|
{
|
||||||
|
/* Adjust pointer into the memory block. */
|
||||||
|
key_copy = (char *) newp + (key_copy - buffer);
|
||||||
|
|
||||||
|
dataset = memcpy (newp, dataset, total + req->key_len);
|
||||||
|
cacheable = true;
|
||||||
|
|
||||||
|
if (he != NULL)
|
||||||
|
/* Mark the old record as obsolete. */
|
||||||
|
dh->usable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (he == NULL && fd != -1)
|
||||||
|
{
|
||||||
|
/* We write the dataset before inserting it to the database
|
||||||
|
since while inserting this thread might block and so would
|
||||||
|
unnecessarily let the receiver wait. */
|
||||||
|
writeout:
|
||||||
|
#ifdef HAVE_SENDFILE
|
||||||
|
if (__builtin_expect (db->mmap_used, 1) && cacheable)
|
||||||
|
{
|
||||||
|
assert (db->wr_fd != -1);
|
||||||
|
assert ((char *) &dataset->resp > (char *) db->data);
|
||||||
|
assert ((char *) dataset - (char *) db->head + total
|
||||||
|
<= (sizeof (struct database_pers_head)
|
||||||
|
+ db->head->module * sizeof (ref_t)
|
||||||
|
+ db->head->data_size));
|
||||||
|
# ifndef __ASSUME_SENDFILE
|
||||||
|
ssize_t written =
|
||||||
|
# endif
|
||||||
|
sendfileall (fd, db->wr_fd, (char *) &dataset->resp
|
||||||
|
- (char *) db->head, dataset->head.recsize);
|
||||||
|
# ifndef __ASSUME_SENDFILE
|
||||||
|
if (written == -1 && errno == ENOSYS)
|
||||||
|
goto use_write;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# ifndef __ASSUME_SENDFILE
|
||||||
|
use_write:
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
writeall (fd, &dataset->resp, dataset->head.recsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacheable)
|
||||||
|
{
|
||||||
|
/* If necessary, we also propagate the data to disk. */
|
||||||
|
if (db->persistent)
|
||||||
|
{
|
||||||
|
// XXX async OK?
|
||||||
|
uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
|
||||||
|
msync ((void *) pval,
|
||||||
|
((uintptr_t) dataset & pagesize_m1) + total + req->key_len,
|
||||||
|
MS_ASYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
|
||||||
|
true, db, uid, he == NULL);
|
||||||
|
|
||||||
|
pthread_rwlock_unlock (&db->lock);
|
||||||
|
|
||||||
|
/* Mark the old entry as obsolete. */
|
||||||
|
if (dh != NULL)
|
||||||
|
dh->usable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (use_malloc)
|
||||||
|
free (buffer);
|
||||||
|
|
||||||
|
*resultp = dataset;
|
||||||
|
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static time_t
|
||||||
|
addinnetgrX (struct database_dyn *db, int fd, request_header *req,
|
||||||
|
char *key, uid_t uid, struct hashentry *he,
|
||||||
|
struct datahead *dh)
|
||||||
|
{
|
||||||
|
const char *group = key;
|
||||||
|
key = (char *) rawmemchr (key, '\0') + 1;
|
||||||
|
size_t group_len = key - group - 1;
|
||||||
|
const char *host = *key++ ? key : NULL;
|
||||||
|
if (host != NULL)
|
||||||
|
key = (char *) rawmemchr (key, '\0') + 1;
|
||||||
|
const char *user = *key++ ? key : NULL;
|
||||||
|
if (user != NULL)
|
||||||
|
key = (char *) rawmemchr (key, '\0') + 1;
|
||||||
|
const char *domain = *key++ ? key : NULL;
|
||||||
|
|
||||||
|
if (__builtin_expect (debug_level > 0, 0))
|
||||||
|
{
|
||||||
|
if (he == NULL)
|
||||||
|
dbg_log (_("Haven't found \"%s (%s,%s,%s)\" in netgroup cache!"),
|
||||||
|
group, host ?: "", user ?: "", domain ?: "");
|
||||||
|
else
|
||||||
|
dbg_log (_("Reloading \"%s (%s,%s,%s)\" in netgroup cache!"),
|
||||||
|
group, host ?: "", user ?: "", domain ?: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dataset *result = (struct dataset *) cache_search (GETNETGRENT,
|
||||||
|
group, group_len,
|
||||||
|
db, uid);
|
||||||
|
time_t timeout;
|
||||||
|
if (result != NULL)
|
||||||
|
timeout = result->head.timeout;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request_header req_get =
|
||||||
|
{
|
||||||
|
.type = GETNETGRENT,
|
||||||
|
.key_len = group_len
|
||||||
|
};
|
||||||
|
timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
|
||||||
|
&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct indataset
|
||||||
|
{
|
||||||
|
struct datahead head;
|
||||||
|
innetgroup_response_header resp;
|
||||||
|
} *dataset
|
||||||
|
= (struct indataset *) mempool_alloc (db,
|
||||||
|
sizeof (*dataset) + req->key_len,
|
||||||
|
1);
|
||||||
|
struct indataset dataset_mem;
|
||||||
|
bool cacheable = true;
|
||||||
|
if (__builtin_expect (dataset == NULL, 0))
|
||||||
|
{
|
||||||
|
cacheable = false;
|
||||||
|
dataset = &dataset_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataset->head.allocsize = sizeof (*dataset) + req->key_len;
|
||||||
|
dataset->head.recsize = sizeof (innetgroup_response_header);
|
||||||
|
dataset->head.notfound = result->head.notfound;
|
||||||
|
dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
|
||||||
|
dataset->head.usable = true;
|
||||||
|
dataset->head.ttl = result->head.ttl;
|
||||||
|
dataset->head.timeout = timeout;
|
||||||
|
|
||||||
|
dataset->resp.version = NSCD_VERSION;
|
||||||
|
dataset->resp.found = result->resp.found;
|
||||||
|
/* Until we find a matching entry the result is 0. */
|
||||||
|
dataset->resp.result = 0;
|
||||||
|
|
||||||
|
char *key_copy = memcpy ((char *) (dataset + 1), group, req->key_len);
|
||||||
|
|
||||||
|
if (dataset->resp.found)
|
||||||
|
{
|
||||||
|
const char *triplets = (const char *) (&result->resp + 1);
|
||||||
|
|
||||||
|
for (nscd_ssize_t i = result->resp.nresults; i > 0; --i)
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
if (host != NULL)
|
||||||
|
success = strcmp (host, triplets) == 0;
|
||||||
|
triplets = (const char *) rawmemchr (triplets, '\0') + 1;
|
||||||
|
|
||||||
|
if (success && user != NULL)
|
||||||
|
success = strcmp (user, triplets) == 0;
|
||||||
|
triplets = (const char *) rawmemchr (triplets, '\0') + 1;
|
||||||
|
|
||||||
|
if (success && (domain == NULL || strcmp (domain, triplets) == 0))
|
||||||
|
{
|
||||||
|
dataset->resp.result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
triplets = (const char *) rawmemchr (triplets, '\0') + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (he != NULL && dh->data[0].innetgroupdata.result == dataset->resp.result)
|
||||||
|
{
|
||||||
|
/* The data has not changed. We will just bump the timeout
|
||||||
|
value. Note that the new record has been allocated on
|
||||||
|
the stack and need not be freed. */
|
||||||
|
dh->timeout = timeout;
|
||||||
|
dh->ttl = dataset->head.ttl;
|
||||||
|
++dh->nreloads;
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (he == NULL)
|
||||||
|
{
|
||||||
|
/* We write the dataset before inserting it to the database
|
||||||
|
since while inserting this thread might block and so would
|
||||||
|
unnecessarily let the receiver wait. */
|
||||||
|
assert (fd != -1);
|
||||||
|
|
||||||
|
#ifdef HAVE_SENDFILE
|
||||||
|
if (__builtin_expect (db->mmap_used, 1) && cacheable)
|
||||||
|
{
|
||||||
|
assert (db->wr_fd != -1);
|
||||||
|
assert ((char *) &dataset->resp > (char *) db->data);
|
||||||
|
assert ((char *) dataset - (char *) db->head + sizeof (*dataset)
|
||||||
|
<= (sizeof (struct database_pers_head)
|
||||||
|
+ db->head->module * sizeof (ref_t)
|
||||||
|
+ db->head->data_size));
|
||||||
|
# ifndef __ASSUME_SENDFILE
|
||||||
|
ssize_t written =
|
||||||
|
# endif
|
||||||
|
sendfileall (fd, db->wr_fd,
|
||||||
|
(char *) &dataset->resp - (char *) db->head,
|
||||||
|
sizeof (innetgroup_response_header));
|
||||||
|
# ifndef __ASSUME_SENDFILE
|
||||||
|
if (written == -1 && errno == ENOSYS)
|
||||||
|
goto use_write;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# ifndef __ASSUME_SENDFILE
|
||||||
|
use_write:
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
writeall (fd, &dataset->resp, sizeof (innetgroup_response_header));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacheable)
|
||||||
|
{
|
||||||
|
/* If necessary, we also propagate the data to disk. */
|
||||||
|
if (db->persistent)
|
||||||
|
{
|
||||||
|
// XXX async OK?
|
||||||
|
uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
|
||||||
|
msync ((void *) pval,
|
||||||
|
((uintptr_t) dataset & pagesize_m1) + sizeof (*dataset)
|
||||||
|
+ req->key_len,
|
||||||
|
MS_ASYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
|
||||||
|
true, db, uid, he == NULL);
|
||||||
|
|
||||||
|
pthread_rwlock_unlock (&db->lock);
|
||||||
|
|
||||||
|
/* Mark the old entry as obsolete. */
|
||||||
|
if (dh != NULL)
|
||||||
|
dh->usable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
|
||||||
|
void *key, uid_t uid)
|
||||||
|
{
|
||||||
|
struct dataset *ignore;
|
||||||
|
|
||||||
|
addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
time_t
|
||||||
|
readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
|
||||||
|
struct datahead *dh)
|
||||||
|
{
|
||||||
|
request_header req =
|
||||||
|
{
|
||||||
|
.type = GETNETGRENT,
|
||||||
|
.key_len = he->len
|
||||||
|
};
|
||||||
|
struct dataset *ignore;
|
||||||
|
|
||||||
|
return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
|
||||||
|
&ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
addinnetgr (struct database_dyn *db, int fd, request_header *req,
|
||||||
|
void *key, uid_t uid)
|
||||||
|
{
|
||||||
|
addinnetgrX (db, fd, req, key, uid, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
time_t
|
||||||
|
readdinnetgr (struct database_dyn *db, struct hashentry *he,
|
||||||
|
struct datahead *dh)
|
||||||
|
{
|
||||||
|
request_header req =
|
||||||
|
{
|
||||||
|
.type = INNETGR,
|
||||||
|
.key_len = he->len
|
||||||
|
};
|
||||||
|
|
||||||
|
return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh);
|
||||||
|
}
|
@@ -70,6 +70,9 @@ typedef enum
|
|||||||
GETSERVBYNAME,
|
GETSERVBYNAME,
|
||||||
GETSERVBYPORT,
|
GETSERVBYPORT,
|
||||||
GETFDSERV,
|
GETFDSERV,
|
||||||
|
GETNETGRENT,
|
||||||
|
INNETGR,
|
||||||
|
GETFDNETGR,
|
||||||
LASTREQ
|
LASTREQ
|
||||||
} request_type;
|
} request_type;
|
||||||
|
|
||||||
@@ -171,6 +174,24 @@ typedef struct
|
|||||||
} serv_response_header;
|
} serv_response_header;
|
||||||
|
|
||||||
|
|
||||||
|
/* Structure send in reply to netgroup query. Note that this struct is
|
||||||
|
sent also if the service is disabled or there is no record found. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int32_t version;
|
||||||
|
int32_t found;
|
||||||
|
nscd_ssize_t nresults;
|
||||||
|
nscd_ssize_t result_len;
|
||||||
|
} netgroup_response_header;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int32_t version;
|
||||||
|
int32_t found;
|
||||||
|
int32_t result;
|
||||||
|
} innetgroup_response_header;
|
||||||
|
|
||||||
|
|
||||||
/* Type for offsets in data part of database. */
|
/* Type for offsets in data part of database. */
|
||||||
typedef uint32_t ref_t;
|
typedef uint32_t ref_t;
|
||||||
/* Value for invalid/no reference. */
|
/* Value for invalid/no reference. */
|
||||||
@@ -210,6 +231,8 @@ struct datahead
|
|||||||
ai_response_header aidata;
|
ai_response_header aidata;
|
||||||
initgr_response_header initgrdata;
|
initgr_response_header initgrdata;
|
||||||
serv_response_header servdata;
|
serv_response_header servdata;
|
||||||
|
netgroup_response_header netgroupdata;
|
||||||
|
innetgroup_response_header innetgroupdata;
|
||||||
nscd_ssize_t align1;
|
nscd_ssize_t align1;
|
||||||
nscd_time_t align2;
|
nscd_time_t align2;
|
||||||
} data[0];
|
} data[0];
|
||||||
|
@@ -77,3 +77,12 @@
|
|||||||
persistent services yes
|
persistent services yes
|
||||||
shared services yes
|
shared services yes
|
||||||
max-db-size services 33554432
|
max-db-size services 33554432
|
||||||
|
|
||||||
|
enable-cache netgroup yes
|
||||||
|
positive-time-to-live netgroup 28800
|
||||||
|
negative-time-to-live netgroup 20
|
||||||
|
suggested-size netgroup 211
|
||||||
|
check-files netgroup yes
|
||||||
|
persistent netgroup yes
|
||||||
|
shared netgroup yes
|
||||||
|
max-db-size netgroup 33554432
|
||||||
|
22
nscd/nscd.h
22
nscd/nscd.h
@@ -38,6 +38,7 @@ typedef enum
|
|||||||
grpdb,
|
grpdb,
|
||||||
hstdb,
|
hstdb,
|
||||||
servdb,
|
servdb,
|
||||||
|
netgrdb,
|
||||||
lastdb
|
lastdb
|
||||||
} dbtype;
|
} dbtype;
|
||||||
|
|
||||||
@@ -116,6 +117,7 @@ struct database_dyn
|
|||||||
#define _PATH_NSCD_GROUP_DB "/var/db/nscd/group"
|
#define _PATH_NSCD_GROUP_DB "/var/db/nscd/group"
|
||||||
#define _PATH_NSCD_HOSTS_DB "/var/db/nscd/hosts"
|
#define _PATH_NSCD_HOSTS_DB "/var/db/nscd/hosts"
|
||||||
#define _PATH_NSCD_SERVICES_DB "/var/db/nscd/services"
|
#define _PATH_NSCD_SERVICES_DB "/var/db/nscd/services"
|
||||||
|
#define _PATH_NSCD_NETGROUP_DB "/var/db/nscd/netgroup"
|
||||||
|
|
||||||
/* Path used when not using persistent storage. */
|
/* Path used when not using persistent storage. */
|
||||||
#define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
|
#define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
|
||||||
@@ -149,6 +151,7 @@ extern const struct iovec pwd_iov_disabled;
|
|||||||
extern const struct iovec grp_iov_disabled;
|
extern const struct iovec grp_iov_disabled;
|
||||||
extern const struct iovec hst_iov_disabled;
|
extern const struct iovec hst_iov_disabled;
|
||||||
extern const struct iovec serv_iov_disabled;
|
extern const struct iovec serv_iov_disabled;
|
||||||
|
extern const struct iovec netgroup_iov_disabled;
|
||||||
|
|
||||||
|
|
||||||
/* Initial number of threads to run. */
|
/* Initial number of threads to run. */
|
||||||
@@ -197,6 +200,11 @@ extern gid_t old_gid;
|
|||||||
|
|
||||||
/* Prototypes for global functions. */
|
/* Prototypes for global functions. */
|
||||||
|
|
||||||
|
/* Wrapper functions with error checking for standard functions. */
|
||||||
|
extern void *xmalloc (size_t n);
|
||||||
|
extern void *xcalloc (size_t n, size_t s);
|
||||||
|
extern void *xrealloc (void *o, size_t n);
|
||||||
|
|
||||||
/* nscd.c */
|
/* nscd.c */
|
||||||
extern void termination_handler (int signum) __attribute__ ((__noreturn__));
|
extern void termination_handler (int signum) __attribute__ ((__noreturn__));
|
||||||
extern int nscd_open_socket (void);
|
extern int nscd_open_socket (void);
|
||||||
@@ -216,8 +224,8 @@ extern void send_stats (int fd, struct database_dyn dbs[lastdb]);
|
|||||||
extern int receive_print_stats (void) __attribute__ ((__noreturn__));
|
extern int receive_print_stats (void) __attribute__ ((__noreturn__));
|
||||||
|
|
||||||
/* cache.c */
|
/* cache.c */
|
||||||
extern struct datahead *cache_search (request_type, void *key, size_t len,
|
extern struct datahead *cache_search (request_type, const void *key,
|
||||||
struct database_dyn *table,
|
size_t len, struct database_dyn *table,
|
||||||
uid_t owner);
|
uid_t owner);
|
||||||
extern int cache_add (int type, const void *key, size_t len,
|
extern int cache_add (int type, const void *key, size_t len,
|
||||||
struct datahead *packet, bool first,
|
struct datahead *packet, bool first,
|
||||||
@@ -286,6 +294,16 @@ extern void addservbyport (struct database_dyn *db, int fd,
|
|||||||
extern time_t readdservbyport (struct database_dyn *db, struct hashentry *he,
|
extern time_t readdservbyport (struct database_dyn *db, struct hashentry *he,
|
||||||
struct datahead *dh);
|
struct datahead *dh);
|
||||||
|
|
||||||
|
/* netgroupcache.c */
|
||||||
|
extern void addinnetgr (struct database_dyn *db, int fd, request_header *req,
|
||||||
|
void *key, uid_t uid);
|
||||||
|
extern time_t readdinnetgr (struct database_dyn *db, struct hashentry *he,
|
||||||
|
struct datahead *dh);
|
||||||
|
extern void addgetnetgrent (struct database_dyn *db, int fd,
|
||||||
|
request_header *req, void *key, uid_t uid);
|
||||||
|
extern time_t readdgetnetgrent (struct database_dyn *db, struct hashentry *he,
|
||||||
|
struct datahead *dh);
|
||||||
|
|
||||||
/* mem.c */
|
/* mem.c */
|
||||||
extern void *mempool_alloc (struct database_dyn *db, size_t len,
|
extern void *mempool_alloc (struct database_dyn *db, size_t len,
|
||||||
int data_alloc);
|
int data_alloc);
|
||||||
|
@@ -43,7 +43,8 @@ const char *const dbnames[lastdb] =
|
|||||||
[pwddb] = "passwd",
|
[pwddb] = "passwd",
|
||||||
[grpdb] = "group",
|
[grpdb] = "group",
|
||||||
[hstdb] = "hosts",
|
[hstdb] = "hosts",
|
||||||
[servdb] = "services"
|
[servdb] = "services",
|
||||||
|
[netgrdb] = "netgroup"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
290
nscd/nscd_netgroup.c
Normal file
290
nscd/nscd_netgroup.c
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
/* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
02111-1307 USA. */
|
||||||
|
|
||||||
|
#include <alloca.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <not-cancel.h>
|
||||||
|
|
||||||
|
#include "nscd-client.h"
|
||||||
|
#include "nscd_proto.h"
|
||||||
|
|
||||||
|
int __nss_not_use_nscd_netgroup;
|
||||||
|
|
||||||
|
|
||||||
|
libc_locked_map_ptr (static, map_handle);
|
||||||
|
/* Note that we only free the structure if necessary. The memory
|
||||||
|
mapping is not removed since it is not visible to the malloc
|
||||||
|
handling. */
|
||||||
|
libc_freeres_fn (pw_map_free)
|
||||||
|
{
|
||||||
|
if (map_handle.mapped != NO_MAPPING)
|
||||||
|
{
|
||||||
|
void *p = map_handle.mapped;
|
||||||
|
map_handle.mapped = NO_MAPPING;
|
||||||
|
free (p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
__nscd_setnetgrent (const char *group, struct __netgrent *datap)
|
||||||
|
{
|
||||||
|
int gc_cycle;
|
||||||
|
int nretries = 0;
|
||||||
|
size_t group_len = strlen (group);
|
||||||
|
|
||||||
|
/* If the mapping is available, try to search there instead of
|
||||||
|
communicating with the nscd. */
|
||||||
|
struct mapped_database *mapped;
|
||||||
|
mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
|
||||||
|
|
||||||
|
retry:;
|
||||||
|
char *respdata = NULL;
|
||||||
|
int retval = -1;
|
||||||
|
netgroup_response_header netgroup_resp;
|
||||||
|
|
||||||
|
if (mapped != NO_MAPPING)
|
||||||
|
{
|
||||||
|
struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
|
||||||
|
group_len, mapped,
|
||||||
|
sizeof netgroup_resp);
|
||||||
|
if (found != NULL)
|
||||||
|
{
|
||||||
|
respdata = (char *) (&found->data[0].netgroupdata + 1);
|
||||||
|
netgroup_resp = found->data[0].netgroupdata;
|
||||||
|
/* Now check if we can trust pw_resp fields. If GC is
|
||||||
|
in progress, it can contain anything. */
|
||||||
|
if (mapped->head->gc_cycle != gc_cycle)
|
||||||
|
{
|
||||||
|
retval = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock = -1;
|
||||||
|
if (respdata == NULL)
|
||||||
|
{
|
||||||
|
sock = __nscd_open_socket (group, group_len, GETNETGRENT,
|
||||||
|
&netgroup_resp, sizeof (netgroup_resp));
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
/* nscd not running or wrong version. */
|
||||||
|
__nss_not_use_nscd_netgroup = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netgroup_resp.found == 1)
|
||||||
|
{
|
||||||
|
size_t datalen = netgroup_resp.result_len;
|
||||||
|
|
||||||
|
/* If we do not have to read the data here it comes from the
|
||||||
|
mapped data and does not have to be freed. */
|
||||||
|
if (respdata == NULL)
|
||||||
|
{
|
||||||
|
/* The data will come via the socket. */
|
||||||
|
respdata = malloc (datalen);
|
||||||
|
if (respdata == NULL)
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
if ((size_t) __readall (sock, respdata, datalen) != datalen)
|
||||||
|
{
|
||||||
|
free (respdata);
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
datap->data = respdata;
|
||||||
|
datap->data_size = datalen;
|
||||||
|
datap->cursor = respdata;
|
||||||
|
datap->first = 1;
|
||||||
|
datap->nip = (service_user *) -1l;
|
||||||
|
datap->known_groups = NULL;
|
||||||
|
datap->needed_groups = NULL;
|
||||||
|
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (__builtin_expect (netgroup_resp.found == -1, 0))
|
||||||
|
{
|
||||||
|
/* The daemon does not cache this database. */
|
||||||
|
__nss_not_use_nscd_netgroup = 1;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set errno to 0 to indicate no error, just no found record. */
|
||||||
|
__set_errno (0);
|
||||||
|
/* Even though we have not found anything, the result is zero. */
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (sock != -1)
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
|
out:
|
||||||
|
if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
|
||||||
|
{
|
||||||
|
/* When we come here this means there has been a GC cycle while we
|
||||||
|
were looking for the data. This means the data might have been
|
||||||
|
inconsistent. Retry if possible. */
|
||||||
|
if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
|
||||||
|
{
|
||||||
|
/* nscd is just running gc now. Disable using the mapping. */
|
||||||
|
if (atomic_decrement_val (&mapped->counter) == 0)
|
||||||
|
__nscd_unmap (mapped);
|
||||||
|
mapped = NO_MAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval != -1)
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
__nscd_innetgr (const char *netgroup, const char *host, const char *user,
|
||||||
|
const char *domain)
|
||||||
|
{
|
||||||
|
size_t key_len = (strlen (netgroup) + strlen (host ?: "")
|
||||||
|
+ strlen (user ?: "") + strlen (domain ?: "") + 7);
|
||||||
|
char *key;
|
||||||
|
bool use_alloca = __libc_use_alloca (key_len);
|
||||||
|
if (use_alloca)
|
||||||
|
key = alloca (key_len);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key = malloc (key_len);
|
||||||
|
if (key == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char *wp = stpcpy (key, netgroup) + 1;
|
||||||
|
if (host != NULL)
|
||||||
|
{
|
||||||
|
*wp++ = '\1';
|
||||||
|
wp = stpcpy (wp, host) + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*wp++ = '\0';
|
||||||
|
if (user != NULL)
|
||||||
|
{
|
||||||
|
*wp++ = '\1';
|
||||||
|
wp = stpcpy (wp, user) + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*wp++ = '\0';
|
||||||
|
if (domain != NULL)
|
||||||
|
{
|
||||||
|
*wp++ = '\1';
|
||||||
|
wp = stpcpy (wp, domain) + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*wp++ = '\0';
|
||||||
|
key_len = wp - key;
|
||||||
|
|
||||||
|
/* If the mapping is available, try to search there instead of
|
||||||
|
communicating with the nscd. */
|
||||||
|
int gc_cycle;
|
||||||
|
int nretries = 0;
|
||||||
|
struct mapped_database *mapped;
|
||||||
|
mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
|
||||||
|
|
||||||
|
retry:;
|
||||||
|
int retval = -1;
|
||||||
|
innetgroup_response_header innetgroup_resp;
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
|
if (mapped != NO_MAPPING)
|
||||||
|
{
|
||||||
|
struct datahead *found = __nscd_cache_search (INNETGR, key,
|
||||||
|
key_len, mapped,
|
||||||
|
sizeof innetgroup_resp);
|
||||||
|
if (found != NULL)
|
||||||
|
{
|
||||||
|
innetgroup_resp = found->data[0].innetgroupdata;
|
||||||
|
/* Now check if we can trust pw_resp fields. If GC is
|
||||||
|
in progress, it can contain anything. */
|
||||||
|
if (mapped->head->gc_cycle != gc_cycle)
|
||||||
|
{
|
||||||
|
retval = -2;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto found_entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = __nscd_open_socket (key, key_len, INNETGR,
|
||||||
|
&innetgroup_resp, sizeof (innetgroup_resp));
|
||||||
|
if (sock == -1)
|
||||||
|
{
|
||||||
|
/* nscd not running or wrong version. */
|
||||||
|
__nss_not_use_nscd_netgroup = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
found_entry:
|
||||||
|
if (innetgroup_resp.found == 1)
|
||||||
|
retval = innetgroup_resp.result;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (__builtin_expect (innetgroup_resp.found == -1, 0))
|
||||||
|
{
|
||||||
|
/* The daemon does not cache this database. */
|
||||||
|
__nss_not_use_nscd_netgroup = 1;
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set errno to 0 to indicate no error, just no found record. */
|
||||||
|
__set_errno (0);
|
||||||
|
/* Even though we have not found anything, the result is zero. */
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_close:
|
||||||
|
if (sock != -1)
|
||||||
|
close_not_cancel_no_status (sock);
|
||||||
|
out:
|
||||||
|
if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
|
||||||
|
{
|
||||||
|
/* When we come here this means there has been a GC cycle while we
|
||||||
|
were looking for the data. This means the data might have been
|
||||||
|
inconsistent. Retry if possible. */
|
||||||
|
if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
|
||||||
|
{
|
||||||
|
/* nscd is just running gc now. Disable using the mapping. */
|
||||||
|
if (atomic_decrement_val (&mapped->counter) == 0)
|
||||||
|
__nscd_unmap (mapped);
|
||||||
|
mapped = NO_MAPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval != -1)
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! use_alloca)
|
||||||
|
free (key);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 1998-2000, 2002, 2004, 2007 Free Software Foundation, Inc.
|
/* Copyright (C) 1998-2000,2002,2004,2007,2011 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
|
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ extern int __nss_not_use_nscd_passwd attribute_hidden;
|
|||||||
extern int __nss_not_use_nscd_group attribute_hidden;
|
extern int __nss_not_use_nscd_group attribute_hidden;
|
||||||
extern int __nss_not_use_nscd_hosts attribute_hidden;
|
extern int __nss_not_use_nscd_hosts attribute_hidden;
|
||||||
extern int __nss_not_use_nscd_services attribute_hidden;
|
extern int __nss_not_use_nscd_services attribute_hidden;
|
||||||
|
extern int __nss_not_use_nscd_netgroup attribute_hidden;
|
||||||
|
|
||||||
extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
|
extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
|
||||||
char *buffer, size_t buflen,
|
char *buffer, size_t buflen,
|
||||||
@@ -71,5 +72,7 @@ extern int __nscd_getservbyname_r (const char *name, const char *proto,
|
|||||||
extern int __nscd_getservbyport_r (int port, const char *proto,
|
extern int __nscd_getservbyport_r (int port, const char *proto,
|
||||||
struct servent *result_buf, char *buf,
|
struct servent *result_buf, char *buf,
|
||||||
size_t buflen, struct servent **result);
|
size_t buflen, struct servent **result);
|
||||||
|
extern int __nscd_innetgr (const char *netgroup, const char *host,
|
||||||
|
const char *user, const char *domain);
|
||||||
|
|
||||||
#endif /* _NSCD_PROTO_H */
|
#endif /* _NSCD_PROTO_H */
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* SELinux access controls for nscd.
|
/* SELinux access controls for nscd.
|
||||||
Copyright (C) 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
|
Copyright (C) 2004,2005,2006,2007,2009,2011 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
|
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
int selinux_enabled;
|
int selinux_enabled;
|
||||||
|
|
||||||
/* Define mappings of access vector permissions to request types. */
|
/* Define mappings of access vector permissions to request types. */
|
||||||
static const int perms[LASTREQ] =
|
static const access_vector_t perms[LASTREQ] =
|
||||||
{
|
{
|
||||||
[GETPWBYNAME] = NSCD__GETPWD,
|
[GETPWBYNAME] = NSCD__GETPWD,
|
||||||
[GETPWBYUID] = NSCD__GETPWD,
|
[GETPWBYUID] = NSCD__GETPWD,
|
||||||
@@ -69,6 +69,11 @@ static const int perms[LASTREQ] =
|
|||||||
[GETSERVBYPORT] = NSCD__GETSERV,
|
[GETSERVBYPORT] = NSCD__GETSERV,
|
||||||
[GETFDSERV] = NSCD__SHMEMSERV,
|
[GETFDSERV] = NSCD__SHMEMSERV,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NSCD__GETNETGRP
|
||||||
|
[GETNETGRENT] = NSCD__GETNETGRP,
|
||||||
|
[INNETGR] = NSCD__GETNETGRP,
|
||||||
|
[GETFDNETGR] = NSCD__SHMEMNETGRP,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Store an entry ref to speed AVC decisions. */
|
/* Store an entry ref to speed AVC decisions. */
|
||||||
|
@@ -12,7 +12,7 @@ libc {
|
|||||||
__nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent;
|
__nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent;
|
||||||
|
|
||||||
__nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
|
__nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
|
||||||
__nss_services_lookup2; __nss_next2;
|
__nss_services_lookup2; __nss_next2; __nss_lookup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
nss/getent.c
18
nss/getent.c
@@ -480,18 +480,28 @@ netgroup_keys (int number, char *key[])
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < number; ++i)
|
if (number == 4)
|
||||||
{
|
{
|
||||||
if (!setnetgrent (key[i]))
|
char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
|
||||||
|
char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
|
||||||
|
char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
|
||||||
|
|
||||||
|
printf ("%-21s (%s,%s,%s) = %d\n",
|
||||||
|
key[0], host ?: "", user ?: "", domain ?: "",
|
||||||
|
innetgr (key[0], host, user, domain));
|
||||||
|
}
|
||||||
|
else if (number == 1)
|
||||||
|
{
|
||||||
|
if (!setnetgrent (key[0]))
|
||||||
result = 2;
|
result = 2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *p[3];
|
char *p[3];
|
||||||
|
|
||||||
printf ("%-21s", key[i]);
|
printf ("%-21s", key[0]);
|
||||||
|
|
||||||
while (getnetgrent (p, p + 1, p + 2))
|
while (getnetgrent (p, p + 1, p + 2))
|
||||||
printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
|
printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
|
||||||
putchar_unlocked ('\n');
|
putchar_unlocked ('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,7 @@ TF (grp, "/etc/group");
|
|||||||
TF (hst, "/etc/hosts");
|
TF (hst, "/etc/hosts");
|
||||||
TF (resolv, "/etc/resolv.conf", .call_res_init = 1);
|
TF (resolv, "/etc/resolv.conf", .call_res_init = 1);
|
||||||
TF (serv, "/etc/services");
|
TF (serv, "/etc/services");
|
||||||
|
TF (netgr, "/etc/netgroup");
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -52,4 +53,6 @@ _nss_files_init (void (*cb) (size_t, struct traced_file *))
|
|||||||
cb (hstdb, &resolv_traced_file.file);
|
cb (hstdb, &resolv_traced_file.file);
|
||||||
|
|
||||||
cb (servdb, &serv_traced_file.file);
|
cb (servdb, &serv_traced_file.file);
|
||||||
|
|
||||||
|
cb (netgrdb, &netgr_traced_file.file);
|
||||||
}
|
}
|
||||||
|
@@ -176,6 +176,7 @@ __nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name,
|
|||||||
|
|
||||||
return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
|
return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
libc_hidden_def (__nss_lookup)
|
||||||
|
|
||||||
|
|
||||||
/* -1 == not found
|
/* -1 == not found
|
||||||
@@ -812,6 +813,7 @@ __nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
|
|||||||
__nss_not_use_nscd_group = -1;
|
__nss_not_use_nscd_group = -1;
|
||||||
__nss_not_use_nscd_hosts = -1;
|
__nss_not_use_nscd_hosts = -1;
|
||||||
__nss_not_use_nscd_services = -1;
|
__nss_not_use_nscd_services = -1;
|
||||||
|
__nss_not_use_nscd_netgroup = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -125,7 +125,8 @@ libc_hidden_proto (__nss_database_lookup)
|
|||||||
position is remembered in NI. The function returns a value < 0 if
|
position is remembered in NI. The function returns a value < 0 if
|
||||||
an error occurred or no such function exists. */
|
an error occurred or no such function exists. */
|
||||||
extern int __nss_lookup (service_user **ni, const char *fct_name,
|
extern int __nss_lookup (service_user **ni, const char *fct_name,
|
||||||
const char *fct2_name, void **fctp) attribute_hidden;
|
const char *fct2_name, void **fctp);
|
||||||
|
libc_hidden_proto (__nss_lookup)
|
||||||
|
|
||||||
/* Determine the next step in the lookup process according to the
|
/* Determine the next step in the lookup process according to the
|
||||||
result STATUS of the call to the last function returned by
|
result STATUS of the call to the last function returned by
|
||||||
|
Reference in New Issue
Block a user