1
0
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:
Ulrich Drepper
2011-10-07 10:06:31 -04:00
parent 21fd49a9ef
commit 684ae51599
19 changed files with 1196 additions and 30 deletions

View File

@@ -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
View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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;

View File

@@ -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
View 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, &notfound, 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, &notfound, 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);
}

View File

@@ -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];

View File

@@ -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

View File

@@ -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);

View File

@@ -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
View 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;
}

View File

@@ -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 */

View File

@@ -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. */

View File

@@ -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;
} }
} }

View File

@@ -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');
} }
} }

View File

@@ -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);
} }

View 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

View File

@@ -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