= Implement name service switch modules (NSS modules). NSS modules

may be built into libc (`static NSS modules') or dynamically loaded
  via dlopen (`dynamic NSS modules').  Modules are loaded/initialized
  at configuration time (i.e.  when nsdispatch is called and nsswitch.conf
  is read or re-read).

= Make the nsdispatch(3) core thread-safe.

= New status code for nsdispatch(3) `NS_RETURN', currently used to
  signal ERANGE-type issues.

= syslog(3) problems, don't warn/err/abort.

= Try harder to avoid namespace pollution.

= Implement some shims to assist in porting NSS modules written for
  the GNU C Library nsswitch interface.

Sponsored by:	DARPA, Network Associates Laboratories
This commit is contained in:
Jacques Vidrine 2003-04-17 14:14:22 +00:00
parent 7f6bf1d8ce
commit 46d9306383
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=113595
14 changed files with 1103 additions and 219 deletions

View File

@ -13,7 +13,8 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h ctype.h db.h \
fts.h getopt.h glob.h grp.h hesiod.h histedit.h ieeefp.h ifaddrs.h \
inttypes.h iso646.h kenv.h langinfo.h libgen.h limits.h link.h \
locale.h malloc.h memory.h monetary.h mpool.h ndbm.h netconfig.h \
netdb.h nl_types.h nlist.h nsswitch.h objformat.h paths.h pthread.h \
netdb.h nl_types.h nlist.h nss.h nsswitch.h objformat.h paths.h \
pthread.h \
pthread_np.h pwd.h ranlib.h readpassphrase.h regex.h regexp.h \
resolv.h rune.h runetype.h search.h setjmp.h sgtty.h signal.h stab.h \
stdbool.h stddef.h stdio.h stdlib.h strhash.h string.h stringlist.h \

56
include/nss.h Normal file
View File

@ -0,0 +1,56 @@
/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*
* Compatibility header for the GNU C Library-style nsswitch interface.
*/
#ifndef _NSS_H_
#define _NSS_H_
#include <nsswitch.h>
enum nss_status {
NSS_STATUS_TRYAGAIN = -2,
NSS_STATUS_UNAVAIL,
NSS_STATUS_NOTFOUND,
NSS_STATUS_SUCCESS,
NSS_STATUS_RETURN
};
#define __nss_compat_result(rv) \
((rv == NSS_STATUS_TRYAGAIN) ? NS_TRYAGAIN : \
(rv == NSS_STATUS_UNAVAIL) ? NS_UNAVAIL : \
(rv == NSS_STATUS_NOTFOUND) ? NS_NOTFOUND : \
(rv == NSS_STATUS_SUCCESS) ? NS_SUCCESS : \
(rv == NSS_STATUS_RETURN) ? NS_RETURN : 0)
#endif

View File

@ -41,20 +41,24 @@
#define _NSSWITCH_H 1
#include <sys/types.h>
#include <stdarg.h>
#define NSS_MODULE_INTERFACE_VERSION 1
#ifndef _PATH_NS_CONF
#define _PATH_NS_CONF "/etc/nsswitch.conf"
#endif
#define NS_CONTINUE 0
#define NS_RETURN 1
/* NSS source actions */
#define NS_ACTION_CONTINUE 0 /* try the next source */
#define NS_ACTION_RETURN 1 /* look no further */
#define NS_SUCCESS (1<<0) /* entry was found */
#define NS_UNAVAIL (1<<1) /* source not responding, or corrupt */
#define NS_NOTFOUND (1<<2) /* source responded 'no such entry' */
#define NS_TRYAGAIN (1<<3) /* source busy, may respond to retrys */
#define NS_TRYAGAIN (1<<3) /* source busy, may respond to retry */
#define NS_RETURN (1<<4) /* stop search, e.g. for ERANGE */
#define NS_TERMINATE (NS_SUCCESS|NS_RETURN) /* flags that end search */
#define NS_STATUSMASK 0x000000ff /* bitmask to get the status flags */
/*
@ -98,13 +102,26 @@
#define NSDB_TTYS "ttys"
/*
* ns_dtab - `nsswitch dispatch table'
* contains an entry for each source and the appropriate function to call
* ns_dtab `method' function signature.
*/
typedef int (*nss_method)(void *_retval, void *_mdata, va_list _ap);
/*
* Macro for generating method prototypes.
*/
typedef struct {
const char *src;
int (*callback)(void *retval, void *cb_data, va_list ap);
void *cb_data;
#define NSS_METHOD_PROTOTYPE(method) \
int method(void *, void *, va_list)
/*
* ns_dtab - `nsswitch dispatch table'
* Contains an entry for each source and the appropriate function to
* call. ns_dtabs are used in the nsdispatch() API in order to allow
* the application to override built-in actions.
*/
typedef struct _ns_dtab {
const char *src; /* Source this entry implements */
nss_method method; /* Method to be called */
void *mdata; /* Data passed to method */
} ns_dtab;
/*
@ -130,7 +147,7 @@ typedef struct {
* used by the nsparser routines to store a mapping between a source
* and its dispatch control flags for a given database.
*/
typedef struct {
typedef struct _ns_src {
const char *name;
u_int32_t flags;
} ns_src;
@ -142,6 +159,38 @@ typedef struct {
*/
extern const ns_src __nsdefaultsrc[];
/*
* ns_mtab - NSS method table
* An NSS module provides a mapping from (database name, method name)
* tuples to the nss_method and associated data.
*/
typedef struct _ns_mtab {
const char *database;
const char *name;
nss_method method;
void *mdata;
} ns_mtab;
/*
* NSS module de-registration, called at module unload.
*/
typedef void (*nss_module_unregister_fn)(ns_mtab *, unsigned int);
/*
* NSS module registration, called at module load.
*/
typedef ns_mtab *(*nss_module_register_fn)(const char *, unsigned int *,
nss_module_unregister_fn *);
/*
* Many NSS interfaces follow the getXXnam, getXXid, getXXent pattern.
* Developers are encouraged to use nss_lookup_type where approriate.
*/
enum nss_lookup_type {
nss_lt_name = 1,
nss_lt_id = 2,
nss_lt_all = 3
};
#ifdef _NS_PRIVATE
@ -154,12 +203,23 @@ extern const ns_src __nsdefaultsrc[];
* for each database in /etc/nsswitch.conf there is a ns_dbt, with its
* name and a list of ns_src's containing the source information.
*/
typedef struct {
typedef struct _ns_dbt {
const char *name; /* name of database */
ns_src *srclist; /* list of sources */
int srclistsize; /* size of srclist */
} ns_dbt;
/*
* ns_mod - NSS module
*/
typedef struct _ns_mod {
char *name; /* module name */
void *handle; /* handle from dlopen */
ns_mtab *mtab; /* method table */
unsigned int mtabsize; /* count of entries in method table */
nss_module_unregister_fn unregister; /* called to unload module */
} ns_mod;
#endif /* _NS_PRIVATE */
@ -171,12 +231,14 @@ extern int nsdispatch(void *, const ns_dtab [], const char *,
#ifdef _NS_PRIVATE
extern void _nsdbtaddsrc(ns_dbt *, const ns_src *);
extern void _nsdbtdump(const ns_dbt *);
extern const ns_dbt *_nsdbtget(const char *);
extern void _nsdbtput(const ns_dbt *);
extern void _nsyyerror(const char *);
extern int _nsyylex(void);
extern int _nsyyparse(void);
extern int _nsyylineno;
#ifdef _NSS_DEBUG
extern void _nsdbtdump(const ns_dbt *);
#endif
#endif /* _NS_PRIVATE */
__END_DECLS

View File

@ -93,7 +93,9 @@ MLINKS+=getnetgrent.3 endnetgrent.3 getnetgrent.3 innetgr.3 \
getnetgrent.3 setnetgrent.3
MLINKS+=getprogname.3 setprogname.3
MLINKS+=getpwent.3 endpwent.3 getpwent.3 getpwnam.3 getpwent.3 getpwuid.3 \
getpwent.3 setpassent.3 getpwent.3 setpwent.3 getpwent.3 setpwfile.3
getpwent.3 setpassent.3 getpwent.3 setpwent.3 getpwent.3 setpwfile.3 \
getpwent.3 getpwent_r.3 getpwent.3 getpwnam_r.3 \
getpwent.3 getpwuid_r.3
MLINKS+=getttyent.3 endttyent.3 getttyent.3 getttynam.3 \
getttyent.3 isdialuptty.3 getttyent.3 isnettty.3 \
getttyent.3 setttyent.3

View File

@ -42,6 +42,7 @@
*/
#define err _err
#define warn _warn
#define nsdispatch _nsdispatch
/*
* Prototypes for syscalls/functions that need to be overridden

View File

@ -0,0 +1,80 @@
/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*
* Macros which generate thread local storage handling code in NSS modules.
*/
#ifndef _NSS_TLS_H_
#define _NSS_TLS_H_
#define NSS_TLS_HANDLING(name) \
static pthread_key_t name##_state_key; \
static void name##_keyinit(void); \
static int name##_getstate(struct name##_state **); \
\
static void \
name##_keyinit(void) \
{ \
(void)_pthread_key_create(&name##_state_key, name##_endstate); \
} \
\
static int \
name##_getstate(struct name##_state **p) \
{ \
static struct name##_state st; \
static pthread_once_t keyinit = PTHREAD_ONCE_INIT; \
int rv; \
\
if (!__isthreaded || _pthread_main_np() != 0) { \
*p = &st; \
return (0); \
} \
rv = _pthread_once(&keyinit, name##_keyinit); \
if (rv != 0) \
return (rv); \
*p = _pthread_getspecific(name##_state_key); \
if (*p != NULL) \
return (0); \
*p = calloc(1, sizeof(*p)); \
if (*p == NULL) \
return (ENOMEM); \
rv = _pthread_setspecific(name##_state_key, *p); \
if (rv != 0) { \
free(*p); \
*p = NULL; \
} \
return (rv); \
} \
/* allow the macro invocation to end with a semicolon */ \
typedef int _##name##_bmVjdGFy
#endif /* _NSS_TLS_H_ */

View File

@ -148,5 +148,6 @@ int _flock(int, int);
#undef err
#undef warn
#undef nsdispatch
#endif /* _UN_NAMESPACE_H_ */

View File

@ -15,7 +15,7 @@ SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c getaddrinfo.c \
inet_netof.c inet_network.c inet_ntoa.c inet_ntop.c \
inet_pton.c ip6opt.c linkaddr.c map_v4v6.c name6.c \
ns_name.c ns_netint.c ns_parse.c ns_print.c ns_ttl.c \
nsdispatch.c nslexer.c nsparser.c \
nsdispatch.c nslexer.c nsparser.c nss_compat.c \
nsap_addr.c rcmd.c rcmdsh.c recv.c res_comp.c res_data.c res_debug.c \
res_init.c res_mkquery.c res_mkupdate.c res_query.c res_send.c \
res_update.c rthdr.c send.c sockatmark.c vars.c

View File

@ -35,7 +35,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd January 19, 1999
.Dd April 16, 2003
.Dt NSDISPATCH 3
.Os
.Sh NAME
@ -44,98 +44,111 @@
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In sys/types.h
.In stdarg.h
.In nsswitch.h
.Ft int
.Fo nsdispatch
.Fa "void *retval"
.Fa "const ns_dtab dtab[]"
.Fa "const char *database"
.Fa "const char *method"
.Fa "const char *method_name"
.Fa "const ns_src defaults[]"
.Fa "..."
.Fc
.Sh DESCRIPTION
The
.Fn nsdispatch
function invokes the callback functions specified in
function invokes the methods specified in
.Va dtab
in the order given in
.Pa /etc/nsswitch.conf
in the order given by
.Xr nsswitch.conf 5
for the database
.Va database
until a successful entry is found.
.Pp
.Va retval
is passed to each callback function to modify as necessary
(to pass back to the caller of
.Fn nsdispatch )
is passed to each method to modify as necessary, to pass back results to
the caller of
.Fn nsdispatch .
.Pp
Each method has the function signature described by the typedef:
.Pp
.Ft typedef "int \*(lp*nss_method\*(rp\*(lpvoid *retval, void *mdata, va_list *ap\*(rp" ;
.Pp
.Va dtab
is an array of
.Va ns_dtab
structures, which have the following format:
.Bd -literal -offset indent
typedef struct {
const char *src;
int (*cb)(void *retval, void *cb_data, va_list ap);
void *cb_data;
typedef struct _ns_dtab {
const char *src;
nss_method method;
void *mdata;
} ns_dtab;
.Ed
.Pp
.Bd -ragged -offset indent
For each source type that is implemented, an entry with
The
.Fa dtab
array should consist of one entry for each source type that is
implemented, with
.Va src
set to the name of the source,
.Va cb
defined as a function which handles that source, and
.Va cb_data
is used to pass arbitrary data to the callback function.
as the name of the source,
.Va method
as a function which handles that source, and
.Va mdata
as a handle on arbitrary data to be passed to the method.
The last entry in
.Va dtab
should contain
.Dv NULL
values for
.Va src ,
.Va cb ,
.Va method ,
and
.Va cb_data .
.Va mdata .
.Ed
.Pp
.Va method
is usually the name of the function calling
.Fn nsdispatch .
When dynamic loading is supported, a symbol constructed from
.Va database ,
the current source, and
.Va method
will be used as the name to invoke the dynamically loaded function.
Additionally, methods may be implemented in NSS modules, in
which case they are selected using the
.Fa database
and
.Fa method_name
arguments along with the configured source.
(The methods supplied via
.Fa dtab
take priority over those implemented in NSS modules in the event
of a conflict.)
.Pp
.Va defaults
contains a list of default sources to try in the case of
a missing or corrupt
.Xr nsswitch.conf 5 ,
or if there isn't a relevant entry for
contains a list of default sources to try if
.Xr nsswitch.conf 5
is missing or corrupted, or if there is no relevant entry for
.Va database .
It is an array of
.Va ns_src
structures, which have the following format:
.Bd -literal -offset indent
typedef struct {
const char *src;
u_int32_t flags;
typedef struct _ns_src {
const char *src;
u_int32_t flags;
} ns_src;
.Ed
.Pp
.Bd -ragged -offset indent
For each default source type, an entry with
.Va src
set to the name of the source, and
The
.Fa defaults
array should consist of one entry for each source to be configured by
default indicated by
.Va src ,
and
.Va flags
set to the relevant flags
set to the criterion desired
(usually
.Dv NS_SUCCESS ;
refer to
.Sx Callback return values
.Sx Method return values
for more information).
The last entry in
.Va defaults
@ -149,18 +162,18 @@ set to 0.
.Pp
For convenience, a global variable defined as:
.Dl extern const ns_src __nsdefaultsrc[];
exists which contains a single default entry for
exists which contains a single default entry for the source
.Sq files
for use by callers which don't require complicated default rules.
that may be used by callers which do not require complicated default
rules.
.Ed
.Pp
.Sq Va ...
are optional extra arguments, which
are passed to the appropriate callback function as a variable argument
list of the type
.Va va_list .
are optional extra arguments, which are passed to the appropriate method
as a variable argument list of the type
.Vt va_list .
.Ss Valid source types
Whilst there is support for arbitrary sources, the following
While there is support for arbitrary sources, the following
#defines for commonly implemented sources are available:
.Bl -column NS_COMPAT COMPAT -offset indent
.It Sy "#define value"
@ -174,29 +187,32 @@ Refer to
.Xr nsswitch.conf 5
for a complete description of what each source type is.
.Pp
.Ss Callback return values
The callback functions should return one of the following values
depending upon status of the lookup:
.Bl -column NS_NOTFOUND -offset indent
.Ss Method return values
The
.Vt nss_method
functions must return one of the following values depending upon status
of the lookup:
.Bl -column "RETURN VALUE" "STATUS CODE"
.It Sy "Return value Status code"
.It "NS_SUCCESS success"
.It "NS_NOTFOUND notfound"
.It "NS_UNAVAIL unavail"
.It "NS_TRYAGAIN tryagain"
.It "NS_RETURN -none-"
.El
.Pp
Refer to
.Xr nsswitch.conf 5
for a complete description of what each status code is.
for a complete description of each status code.
.Pp
The
.Fn nsdispatch
function returns the value of the callback that caused the dispatcher to
finish, or NS_NOTFOUND otherwise.
function returns the value of the method that caused the dispatcher to
terminate, or NS_NOTFOUND otherwise.
.Sh SEE ALSO
.Xr hesiod 3 ,
.Xr stdarg 3 ,
.Xr ypclnt 3 ,
.Xr yp 8 ,
.Xr nsswitch.conf 5
.Sh HISTORY
The
@ -208,25 +224,22 @@ It was imported from the
Project,
where it appeared first in
.Nx 1.4 .
Support for NSS modules first appeared in
.Fx 5.1 .
.Sh AUTHORS
Luke Mewburn
.Aq lukem@netbsd.org
wrote this freely distributable name-service switch implementation,
wrote this freely-distributable name-service switch implementation,
using ideas from the
.Tn ULTRIX
.Xr svc.conf 5
"svc.conf\*(lp5\*(rp"
and
.Tn Solaris
.Xr nsswitch.conf 4
"nsswitch.conf\*(lp4\*(rp"
manual pages.
.Sh BUGS
The
.Fx Project
added the support for threads and NSS modules, and normalized the uses
of
.Fn nsdispatch
function is not thread safe.
This will be rectified in the future.
.Pp
Currently there is no support for dynamically loadable dispatcher callback
functions.
It is anticipated that this will be added in the future in the back-end
without requiring changes to code that invokes
.Fn nsdispatch .
within the standard C library.

View File

@ -35,25 +35,75 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* Portions of this software were developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include "namespace.h"
#include <err.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#define _NS_PRIVATE
#include <nsswitch.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "un-namespace.h"
enum _nss_constants {
/* Number of elements allocated when we grow a vector */
ELEMSPERCHUNK = 8
};
/*
* Global NSS data structures are mostly read-only, but we update
* them when we read or re-read the nsswitch.conf.
*/
static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER;
/*
* Runtime determination of whether we are dynamically linked or not.
*/
extern int _DYNAMIC __attribute__ ((weak));
#define is_dynamic() (&_DYNAMIC != NULL)
/*
* default sourcelist: `files'
*/
@ -62,53 +112,178 @@ const ns_src __nsdefaultsrc[] = {
{ 0 },
};
static int _nsmapsize = 0;
/* Database, source mappings. */
static unsigned int _nsmapsize;
static ns_dbt *_nsmap = NULL;
/* NSS modules. */
static unsigned int _nsmodsize;
static ns_mod *_nsmod;
/* Placeholder for builtin modules' dlopen `handle'. */
static int __nss_builtin_handle;
static void *nss_builtin_handle = &__nss_builtin_handle;
/*
* size of dynamic array chunk for _nsmap and _nsmap[x].srclist
* Attempt to spew relatively uniform messages to syslog.
*/
#define NSELEMSPERCHUNK 8
#define nss_log(level, fmt, ...) \
syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__)
#define nss_log_simple(level, s) \
syslog((level), "NSSWITCH(%s): " s, __func__)
/*
* Dynamically growable arrays are used for lists of databases, sources,
* and modules. The following `vector' interface is used to isolate the
* common operations.
*/
typedef int (*vector_comparison)(const void *, const void *);
typedef void (*vector_free_elem)(void *);
static void vector_sort(void *, unsigned int, size_t,
vector_comparison);
static void vector_free(void **, unsigned int *, size_t,
vector_free_elem);
static void *vector_ref(unsigned int, void *, unsigned int, size_t);
static void *vector_search(const void *, void *, unsigned int, size_t,
vector_comparison);
static int vector_append(const void *, void **, unsigned int *, size_t);
int _nscmp(const void *, const void *);
/*
* Internal interfaces.
*/
static int string_compare(const void *, const void *);
static int mtab_compare(const void *, const void *);
static int nss_configure(void);
static void ns_dbt_free(ns_dbt *);
static void ns_mod_free(ns_mod *);
static void ns_src_free(ns_src **, int);
static void nss_load_builtin_modules(void);
static void nss_load_module(const char *, nss_module_register_fn);
static void nss_atexit(void);
/* nsparser */
extern FILE *_nsyyin;
int
_nscmp(a, b)
const void *a;
const void *b;
/*
* The vector operations
*/
static void
vector_sort(void *vec, unsigned int count, size_t esize,
vector_comparison comparison)
{
return (strcasecmp(((const ns_dbt *)a)->name,
((const ns_dbt *)b)->name));
qsort(vec, count, esize, comparison);
}
void
_nsdbtaddsrc(dbt, src)
ns_dbt *dbt;
const ns_src *src;
static void *
vector_search(const void *key, void *vec, unsigned int count, size_t esize,
vector_comparison comparison)
{
if ((dbt->srclistsize % NSELEMSPERCHUNK) == 0) {
dbt->srclist = (ns_src *)realloc(dbt->srclist,
(dbt->srclistsize + NSELEMSPERCHUNK) * sizeof(ns_src));
if (dbt->srclist == NULL)
_err(1, "nsdispatch: memory allocation failure");
return (bsearch(key, vec, count, esize, comparison));
}
static int
vector_append(const void *elem, void **vec, unsigned int *count, size_t esize)
{
void *p;
if ((*count % ELEMSPERCHUNK) == 0) {
p = realloc(*vec, (*count + ELEMSPERCHUNK) * esize);
if (p == NULL) {
nss_log_simple(LOG_ERR, "memory allocation failure");
return (0);
} else
*vec = p;
}
memmove(&dbt->srclist[dbt->srclistsize++], src, sizeof(ns_src));
memmove((void *)(((uintptr_t)*vec) + (*count * esize)),
elem, esize);
(*count)++;
return (1);
}
static void *
vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize)
{
if (i < count)
return (void *)((uintptr_t)vec + (i * esize));
else
return (NULL);
}
static void
vector_free(void **vec, unsigned int *count, size_t esize,
vector_free_elem free_elem)
{
unsigned int i;
void *elem;
for (i = 0; i < *count; i++) {
elem = vector_ref(i, *vec, *count, esize);
if (elem != NULL)
free_elem(elem);
}
free(*vec);
*vec = NULL;
*count = 0;
}
/*
* Comparison functions for vector_search.
*/
static int
string_compare(const void *a, const void *b)
{
return (strcasecmp(*(const char * const *)a, *(const char * const *)b));
}
static int
mtab_compare(const void *a, const void *b)
{
int cmp;
cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name);
if (cmp != 0)
return (cmp);
else
return (strcmp(((const ns_mtab *)a)->database,
((const ns_mtab *)b)->database));
}
/*
* NSS nsmap management.
*/
void
_nsdbtdump(dbt)
const ns_dbt *dbt;
_nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
{
const ns_mod *modp;
vector_append(src, (void **)&dbt->srclist, &dbt->srclistsize,
sizeof(*src));
modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod),
string_compare);
if (modp == NULL)
nss_load_module(src->name, NULL);
}
#ifdef _NSS_DEBUG
void
_nsdbtdump(const ns_dbt *dbt)
{
int i;
printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
dbt->srclistsize == 1 ? "" : "s");
for (i = 0; i < dbt->srclistsize; i++) {
for (i = 0; i < (int)dbt->srclistsize; i++) {
printf(" %s", dbt->srclist[i].name);
if (!(dbt->srclist[i].flags &
(NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
@ -127,103 +302,285 @@ _nsdbtdump(dbt)
}
printf("\n");
}
#endif
const ns_dbt *
_nsdbtget(name)
const char *name;
/*
* The first time nsdispatch is called (during a process's lifetime,
* or after nsswitch.conf has been updated), nss_configure will
* prepare global data needed by NSS.
*/
static int
nss_configure(void)
{
static time_t confmod;
static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
static time_t confmod;
struct stat statbuf;
ns_dbt dbt;
int result;
const char *path;
extern FILE *_nsyyin;
extern int _nsyyparse(void);
dbt.name = name;
if (confmod) {
if (stat(_PATH_NS_CONF, &statbuf) == -1)
return (NULL);
if (confmod < statbuf.st_mtime) {
int i, j;
for (i = 0; i < _nsmapsize; i++) {
for (j = 0; j < _nsmap[i].srclistsize; j++) {
if (_nsmap[i].srclist[j].name != NULL) {
/*LINTED const cast*/
free((void *)
_nsmap[i].srclist[j].name);
}
}
if (_nsmap[i].srclist)
free(_nsmap[i].srclist);
if (_nsmap[i].name) {
/*LINTED const cast*/
free((void *)_nsmap[i].name);
}
}
if (_nsmap)
free(_nsmap);
_nsmap = NULL;
_nsmapsize = 0;
confmod = 0;
}
}
if (!confmod) {
if (stat(_PATH_NS_CONF, &statbuf) == -1)
return (NULL);
_nsyyin = fopen(_PATH_NS_CONF, "r");
if (_nsyyin == NULL)
return (NULL);
_nsyyparse();
(void)fclose(_nsyyin);
qsort(_nsmap, (size_t)_nsmapsize, sizeof(ns_dbt), _nscmp);
confmod = statbuf.st_mtime;
}
return (bsearch(&dbt, _nsmap, (size_t)_nsmapsize, sizeof(ns_dbt),
_nscmp));
#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT)
/* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built
* for debugging purposes and MUST NEVER be used in production.
*/
path = getenv("NSSWITCH_CONF");
if (path == NULL)
#endif
path = _PATH_NS_CONF;
if (stat(path, &statbuf) != 0)
return (0);
if (statbuf.st_mtime <= confmod)
return (0);
result = _pthread_mutex_trylock(&conf_lock);
if (result != 0)
return (0);
(void)_pthread_rwlock_unlock(&nss_lock);
result = _pthread_rwlock_wrlock(&nss_lock);
if (result != 0)
goto fin2;
_nsyyin = fopen(path, "r");
if (_nsyyin == NULL)
goto fin;
vector_free((void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap),
(vector_free_elem)ns_dbt_free);
vector_free((void **)&_nsmod, &_nsmodsize, sizeof(*_nsmod),
(vector_free_elem)ns_mod_free);
nss_load_builtin_modules();
_nsyyparse();
(void)fclose(_nsyyin);
vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare);
if (confmod == 0)
(void)atexit(nss_atexit);
confmod = statbuf.st_mtime;
fin:
(void)_pthread_rwlock_unlock(&nss_lock);
result = _pthread_rwlock_rdlock(&nss_lock);
fin2:
(void)_pthread_mutex_unlock(&conf_lock);
return (result);
}
void
_nsdbtput(dbt)
const ns_dbt *dbt;
_nsdbtput(const ns_dbt *dbt)
{
int i;
unsigned int i;
ns_dbt *p;
for (i = 0; i < _nsmapsize; i++) {
if (_nscmp(dbt, &_nsmap[i]) == 0) {
/* overwrite existing entry */
if (_nsmap[i].srclist != NULL)
free(_nsmap[i].srclist);
memmove(&_nsmap[i], dbt, sizeof(ns_dbt));
p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
if (string_compare(&dbt->name, &p->name) == 0) {
/* overwrite existing entry */
if (p->srclist != NULL)
ns_src_free(&p->srclist, p->srclistsize);
memmove(p, dbt, sizeof(*dbt));
return;
}
}
if ((_nsmapsize % NSELEMSPERCHUNK) == 0) {
_nsmap = (ns_dbt *)realloc(_nsmap,
(_nsmapsize + NSELEMSPERCHUNK) * sizeof(ns_dbt));
if (_nsmap == NULL)
_err(1, "nsdispatch: memory allocation failure");
}
memmove(&_nsmap[_nsmapsize++], dbt, sizeof(ns_dbt));
vector_append(dbt, (void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap));
}
static void
ns_dbt_free(ns_dbt *dbt)
{
ns_src_free(&dbt->srclist, dbt->srclistsize);
}
static void
ns_src_free(ns_src **src, int srclistsize)
{
int i;
for (i = 0; i < srclistsize; i++)
if ((*src)[i].name != NULL)
/* This one was allocated by nslexer. You'll just
* have to trust me.
*/
free((void *)((*src)[i].name));
free(*src);
*src = NULL;
}
/*
* NSS module management.
*/
/* The built-in NSS modules are all loaded at once. */
#define NSS_BACKEND(name, reg) \
ns_mtab *reg(unsigned int *, nss_module_unregister_fn *);
#include "nss_backends.h"
#undef NSS_BACKEND
static void
nss_load_builtin_modules(void)
{
#define NSS_BACKEND(name, reg) nss_load_module(#name, reg);
#include "nss_backends.h"
#undef NSS_BACKEND
}
/* Load a built-in or dynamically linked module. If the `reg_fn'
* argument is non-NULL, assume a built-in module and use reg_fn to
* register it. Otherwise, search for a dynamic NSS module.
*/
static void
nss_load_module(const char *source, nss_module_register_fn reg_fn)
{
char buf[PATH_MAX];
ns_mod mod;
nss_module_register_fn fn;
memset(&mod, 0, sizeof(mod));
mod.name = strdup(source);
if (mod.name == NULL) {
nss_log_simple(LOG_ERR, "memory allocation failure");
return;
}
if (reg_fn != NULL) {
/* The placeholder is required, as a NULL handle
* represents an invalid module.
*/
mod.handle = nss_builtin_handle;
fn = reg_fn;
} else if (!is_dynamic())
goto fin;
else {
if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
goto fin;
mod.handle = dlopen(buf, RTLD_LOCAL|RTLD_LAZY);
if (mod.handle == NULL) {
#ifdef _NSS_DEBUG
/* This gets pretty annoying since the built-in
* sources aren't modules yet.
*/
nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror());
#endif
goto fin;
}
fn = (nss_module_register_fn)dlfunc(mod.handle,
"nss_module_register");
if (fn == NULL) {
(void)dlclose(mod.handle);
mod.handle = NULL;
nss_log(LOG_ERR, "%s, %s", mod.name, dlerror());
goto fin;
}
}
mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister);
if (mod.mtab == NULL || mod.mtabsize == 0) {
if (mod.handle != nss_builtin_handle)
(void)dlclose(mod.handle);
mod.handle = NULL;
nss_log(LOG_ERR, "%s, registration failed", mod.name);
goto fin;
}
if (mod.mtabsize > 1)
qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
mtab_compare);
fin:
vector_append(&mod, (void **)&_nsmod, &_nsmodsize, sizeof(*_nsmod));
vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare);
}
static void
ns_mod_free(ns_mod *mod)
{
free(mod->name);
if (mod->handle == NULL)
return;
if (mod->unregister != NULL)
mod->unregister(mod->mtab, mod->mtabsize);
if (mod->handle != nss_builtin_handle)
(void)dlclose(mod->handle);
}
/*
* Cleanup
*/
static void
nss_atexit(void)
{
(void)_pthread_rwlock_wrlock(&nss_lock);
vector_free((void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap),
(vector_free_elem)ns_dbt_free);
vector_free((void **)&_nsmod, &_nsmodsize, sizeof(*_nsmod),
(vector_free_elem)ns_mod_free);
(void)_pthread_rwlock_unlock(&nss_lock);
}
/*
* Finally, the actual implementation.
*/
static nss_method
nss_method_lookup(const char *source, const char *database,
const char *method, const ns_dtab disp_tab[], void **mdata)
{
ns_mod *mod;
ns_mtab *match, key;
int i;
if (disp_tab != NULL)
for (i = 0; disp_tab[i].src != NULL; i++)
if (strcasecmp(source, disp_tab[i].src) == 0) {
*mdata = disp_tab[i].mdata;
return (disp_tab[i].method);
}
mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod),
string_compare);
if (mod != NULL && mod->handle != NULL) {
key.database = database;
key.name = method;
match = bsearch(&key, mod->mtab, mod->mtabsize,
sizeof(mod->mtab[0]), mtab_compare);
if (match != NULL) {
*mdata = match->mdata;
return (match->method);
}
}
nss_log(LOG_DEBUG, "%s, %s, %s, not found", source, database, method);
*mdata = NULL;
return (NULL);
}
__weak_reference(_nsdispatch, nsdispatch);
int
nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
const char *method, const ns_src defaults[], ...)
_nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
const char *method_name, const ns_src defaults[], ...)
{
va_list ap;
int i, curdisp, result;
const ns_dbt *dbt;
const ns_src *srclist;
int srclistsize;
nss_method method;
void *mdata;
int serrno, i, result, srclistsize;
dbt = _nsdbtget(database);
serrno = errno;
result = _pthread_rwlock_rdlock(&nss_lock);
if (result != 0) {
result = NS_UNAVAIL;
goto fin;
}
result = nss_configure();
if (result != 0) {
result = NS_UNAVAIL;
goto fin;
}
dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
string_compare);
if (dbt != NULL) {
srclist = dbt->srclist;
srclistsize = dbt->srclistsize;
@ -233,23 +590,20 @@ nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
while (srclist[srclistsize].name != NULL)
srclistsize++;
}
result = 0;
for (i = 0; i < srclistsize; i++) {
for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++)
if (strcasecmp(disp_tab[curdisp].src,
srclist[i].name) == 0)
break;
result = 0;
if (disp_tab[curdisp].callback) {
result = NS_NOTFOUND;
method = nss_method_lookup(srclist[i].name, database,
method_name, disp_tab, &mdata);
if (method != NULL) {
va_start(ap, defaults);
result = disp_tab[curdisp].callback(retval,
disp_tab[curdisp].cb_data, ap);
result = method(retval, mdata, ap);
va_end(ap);
if (result & srclist[i].flags) {
if (result & (srclist[i].flags))
break;
}
}
}
return (result ? result : NS_NOTFOUND);
(void)_pthread_rwlock_unlock(&nss_lock);
fin:
errno = serrno;
return (result);
}

View File

@ -45,10 +45,10 @@ static char *rcsid =
#include "namespace.h"
#include <ctype.h>
#include <err.h>
#define _NS_PRIVATE
#include <nsswitch.h>
#include <string.h>
#include <syslog.h>
#include "un-namespace.h"
#include "nsparser.h"
@ -85,10 +85,11 @@ STRING [a-zA-Z][a-zA-Z0-9_]*
char *p;
int i;
if ((p = strdup(yytext)) == NULL)
_err(1,
"nsdispatch: memory allocation failure");
if ((p = strdup(yytext)) == NULL) {
syslog(LOG_ERR,
"NSSWITCH(nslexer): memory allocation failure");
return ERRORTOKEN;
}
for (i = 0; i < strlen(p); i++) {
if (isupper((unsigned char)p[i]))
p[i] = tolower((unsigned char)p[i]);
@ -113,5 +114,6 @@ _nsyyerror(msg)
const char *msg;
{
warnx("%s line %d: %s at '%s'", _PATH_NS_CONF, yylineno, msg, yytext);
syslog(LOG_ERR, "NSSWITCH(nslexer): %s line %d: %s at '%s'",
_PATH_NS_CONF, yylineno, msg, yytext);
} /* _nsyyerror */

View File

@ -38,17 +38,15 @@
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid =
"$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
__FBSDID("$FreeBSD$");
#include <err.h>
#include "namespace.h"
#define _NS_PRIVATE
#include <nsswitch.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include "un-namespace.h"
static void _nsaddsrctomap(const char *);
@ -64,6 +62,7 @@ static ns_src cursrc;
%token NL
%token SUCCESS UNAVAIL NOTFOUND TRYAGAIN
%token RETURN CONTINUE
%token ERRORTOKEN
%token <str> STRING
%type <mapval> Status Action
@ -110,7 +109,7 @@ Srclist
Item
: STRING
{
cursrc.flags = NS_SUCCESS;
cursrc.flags = NS_TERMINATE;
_nsaddsrctomap($1);
}
| STRING '[' { cursrc.flags = NS_SUCCESS; } Criteria ']'
@ -127,9 +126,9 @@ Criteria
Criterion
: Status '=' Action
{
if ($3) /* if action == RETURN set RETURN bit */
if ($3) /* if action == RETURN set RETURN bit */
cursrc.flags |= $1;
else /* else unset it */
else /* else unset it */
cursrc.flags &= ~$1;
}
;
@ -142,8 +141,8 @@ Status
;
Action
: RETURN { $$ = 1L; }
| CONTINUE { $$ = 0L; }
: RETURN { $$ = NS_ACTION_RETURN; }
| CONTINUE { $$ = NS_ACTION_CONTINUE; }
;
%%
@ -160,16 +159,16 @@ _nsaddsrctomap(elem)
if (curdbt.srclistsize > 0) {
if ((strcasecmp(elem, NSSRC_COMPAT) == 0) ||
(strcasecmp(curdbt.srclist[0].name, NSSRC_COMPAT) == 0)) {
/* XXX: syslog the following */
warnx("%s line %d: 'compat' used with other sources",
syslog(LOG_ERR,
"NSSWITCH(nsparser): %s line %d: 'compat' used with other sources",
_PATH_NS_CONF, lineno);
return;
}
}
for (i = 0; i < curdbt.srclistsize; i++) {
if (strcasecmp(curdbt.srclist[i].name, elem) == 0) {
/* XXX: syslog the following */
warnx("%s line %d: duplicate source '%s'",
syslog(LOG_ERR,
"NSSWITCH(nsparser): %s line %d: duplicate source '%s'",
_PATH_NS_CONF, lineno, elem);
return;
}

View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* Eventually, the implementations of existing built-in NSS functions
* may be moved into NSS modules and live here.
*/
#if 0
NSS_BACKEND( files, _files_nss_module_register )
NSS_BACKEND( dns, _dns_nss_module_register )
NSS_BACKEND( nis, _nis_nss_module_register )
NSS_BACKEND( compat, _compat_nss_module_register )
#endif

270
lib/libc/net/nss_compat.c Normal file
View File

@ -0,0 +1,270 @@
/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Compatibility shims for the GNU C Library-style nsswitch interface.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "namespace.h"
#include <sys/param.h>
#include <nss.h>
#include <pthread.h>
#include <pthread_np.h>
#include "un-namespace.h"
struct group;
struct passwd;
static int terminator;
#define DECLARE_TERMINATOR(x) \
static pthread_key_t _term_key_##x; \
static void \
_term_create_##x(void) \
{ \
(void)_pthread_key_create(&_term_key_##x, NULL); \
} \
static void *_term_main_##x; \
static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT
#define SET_TERMINATOR(x, y) \
do { \
if (_pthread_main_np()) \
_term_main_##x = (y); \
else { \
(void)_pthread_once(&_term_once_##x, _term_create_##x); \
(void)_pthread_setspecific(_term_key_##x, y); \
} \
} while (0)
#define CHECK_TERMINATOR(x) \
(_pthread_main_np() ? \
(_term_main_##x) : \
((void)_pthread_once(&_term_once_##x, _term_create_##x), \
_pthread_getspecific(_term_key_##x)))
DECLARE_TERMINATOR(group);
int
__nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(const char *, struct group *, char *, size_t, int *);
const char *name;
struct group *grp;
char *buffer;
int *errnop;
size_t bufsize;
enum nss_status status;
fn = mdata;
name = va_arg(ap, const char *);
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
status = fn(name, grp, buffer, bufsize, errnop);
if (status == NS_SUCCESS)
*(struct group **)retval = grp;
return (__nss_compat_result(status));
}
int
__nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(gid_t, struct group *, char *, size_t, int *);
gid_t gid;
struct group *grp;
char *buffer;
int *errnop;
size_t bufsize;
enum nss_status status;
fn = mdata;
gid = va_arg(ap, gid_t);
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
status = fn(gid, grp, buffer, bufsize, errnop);
if (status == NS_SUCCESS)
*(struct group **)retval = grp;
return (__nss_compat_result(status));
}
int
__nss_compat_getgrent_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(struct group *, char *, size_t, int *);
struct group *grp;
char *buffer;
int *errnop;
size_t bufsize;
enum nss_status status;
if (CHECK_TERMINATOR(group))
return (NS_NOTFOUND);
fn = mdata;
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
status = fn(grp, buffer, bufsize, errnop);
if (status == NS_SUCCESS)
*(struct group **)retval = grp;
else
SET_TERMINATOR(group, &terminator);
return (__nss_compat_result(status));
}
int
__nss_compat_setgrent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(group, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
int
__nss_compat_endgrent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(group, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
DECLARE_TERMINATOR(passwd);
int
__nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(const char *, struct passwd *, char *, size_t, int *);
const char *name;
struct passwd *pwd;
char *buffer;
int *errnop;
size_t bufsize;
enum nss_status status;
fn = mdata;
name = va_arg(ap, const char *);
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
status = fn(name, pwd, buffer, bufsize, errnop);
if (status == NS_SUCCESS)
*(struct passwd **)retval = pwd;
return (__nss_compat_result(status));
}
int
__nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
uid_t uid;
struct passwd *pwd;
char *buffer;
int *errnop;
size_t bufsize;
enum nss_status status;
fn = mdata;
uid = va_arg(ap, uid_t);
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
status = fn(uid, pwd, buffer, bufsize, errnop);
if (status == NS_SUCCESS)
*(struct passwd **)retval = pwd;
return (__nss_compat_result(status));
}
int
__nss_compat_getpwent_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(struct passwd *, char *, size_t, int *);
struct passwd *pwd;
char *buffer;
int *errnop;
size_t bufsize;
enum nss_status status;
if (CHECK_TERMINATOR(passwd))
return (NS_NOTFOUND);
fn = mdata;
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
status = fn(pwd, buffer, bufsize, errnop);
if (status == NS_SUCCESS)
*(struct passwd **)retval = pwd;
else
SET_TERMINATOR(passwd, &terminator);
return (__nss_compat_result(status));
}
int
__nss_compat_setpwent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(passwd, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
int
__nss_compat_endpwent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(passwd, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}