summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/Makefile3
-rw-r--r--include/nss.h56
-rw-r--r--include/nsswitch.h88
-rw-r--r--lib/libc/gen/Makefile.inc4
-rw-r--r--lib/libc/include/namespace.h1
-rw-r--r--lib/libc/include/nss_tls.h80
-rw-r--r--lib/libc/include/un-namespace.h1
-rw-r--r--lib/libc/net/Makefile.inc2
-rw-r--r--lib/libc/net/nsdispatch.3147
-rw-r--r--lib/libc/net/nsdispatch.c584
-rw-r--r--lib/libc/net/nslexer.l14
-rw-r--r--lib/libc/net/nsparser.y29
-rw-r--r--lib/libc/net/nss_backends.h43
-rw-r--r--lib/libc/net/nss_compat.c270
14 files changed, 1103 insertions, 219 deletions
diff --git a/include/Makefile b/include/Makefile
index 983a939..d5058e0 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -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 \
diff --git a/include/nss.h b/include/nss.h
new file mode 100644
index 0000000..86a08ed
--- /dev/null
+++ b/include/nss.h
@@ -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
diff --git a/include/nsswitch.h b/include/nsswitch.h
index 74e5a90..22e482c 100644
--- a/include/nsswitch.h
+++ b/include/nsswitch.h
@@ -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 `method' function signature.
+ */
+typedef int (*nss_method)(void *_retval, void *_mdata, va_list _ap);
+
+/*
+ * Macro for generating method prototypes.
+ */
+#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
+ * 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 {
- const char *src;
- int (*callback)(void *retval, void *cb_data, va_list ap);
- void *cb_data;
+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
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index d83f526..9ab8616 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -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
diff --git a/lib/libc/include/namespace.h b/lib/libc/include/namespace.h
index f3b430e..e626200 100644
--- a/lib/libc/include/namespace.h
+++ b/lib/libc/include/namespace.h
@@ -42,6 +42,7 @@
*/
#define err _err
#define warn _warn
+#define nsdispatch _nsdispatch
/*
* Prototypes for syscalls/functions that need to be overridden
diff --git a/lib/libc/include/nss_tls.h b/lib/libc/include/nss_tls.h
new file mode 100644
index 0000000..be6b74f
--- /dev/null
+++ b/lib/libc/include/nss_tls.h
@@ -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_ */
diff --git a/lib/libc/include/un-namespace.h b/lib/libc/include/un-namespace.h
index a5cb05f..eaa9471 100644
--- a/lib/libc/include/un-namespace.h
+++ b/lib/libc/include/un-namespace.h
@@ -148,5 +148,6 @@ int _flock(int, int);
#undef err
#undef warn
+#undef nsdispatch
#endif /* _UN_NAMESPACE_H_ */
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index ab9cb36..01dc3b61 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -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
diff --git a/lib/libc/net/nsdispatch.3 b/lib/libc/net/nsdispatch.3
index b87d122..d49a9d5 100644
--- a/lib/libc/net/nsdispatch.3
+++ b/lib/libc/net/nsdispatch.3
@@ -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.
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
index b7c59ff..60a3eba 100644
--- a/lib/libc/net/nsdispatch.c
+++ b/lib/libc/net/nsdispatch.c
@@ -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;
-{
- 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");
+static void *
+vector_search(const void *key, void *vec, unsigned int count, size_t esize,
+ vector_comparison comparison)
+{
+ 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
+_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(dbt)
- const ns_dbt *dbt;
+_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;
-
- 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));
+ int result;
+ const char *path;
+
+#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;
}
}
+ vector_append(dbt, (void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap));
+}
+
+
+static void
+ns_dbt_free(ns_dbt *dbt)
+{
+ ns_src_free(&dbt->srclist, dbt->srclistsize);
+}
- if ((_nsmapsize % NSELEMSPERCHUNK) == 0) {
- _nsmap = (ns_dbt *)realloc(_nsmap,
- (_nsmapsize + NSELEMSPERCHUNK) * sizeof(ns_dbt));
- if (_nsmap == NULL)
- _err(1, "nsdispatch: memory allocation failure");
+
+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;
}
- memmove(&_nsmap[_nsmapsize++], dbt, sizeof(ns_dbt));
+ 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;
-
- dbt = _nsdbtget(database);
+ nss_method method;
+ void *mdata;
+ int serrno, i, result, srclistsize;
+
+ 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);
}
diff --git a/lib/libc/net/nslexer.l b/lib/libc/net/nslexer.l
index ea21072..34c79d9 100644
--- a/lib/libc/net/nslexer.l
+++ b/lib/libc/net/nslexer.l
@@ -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 */
diff --git a/lib/libc/net/nsparser.y b/lib/libc/net/nsparser.y
index dc3be2a..4806dea 100644
--- a/lib/libc/net/nsparser.y
+++ b/lib/libc/net/nsparser.y
@@ -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;
}
diff --git a/lib/libc/net/nss_backends.h b/lib/libc/net/nss_backends.h
new file mode 100644
index 0000000..9bea37b
--- /dev/null
+++ b/lib/libc/net/nss_backends.h
@@ -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
diff --git a/lib/libc/net/nss_compat.c b/lib/libc/net/nss_compat.c
new file mode 100644
index 0000000..8441103
--- /dev/null
+++ b/lib/libc/net/nss_compat.c
@@ -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);
+}
OpenPOWER on IntegriCloud