Following on the NSS (Name Service Switch):

*Step One:  I ported the NetBSD implementation of nsdispatch(3) as implemented 
by Luke Mewburn. See attached patch to libc and new header file. I'm also
attaching the man page for /etc/nsswitch.conf. Right now it compiles,
installs, and works for some simple tests I've run.

*Step Two: make getpwent, getgrent, and friends actually use the nsdispatch
function. I've already started looking at the source, but am having trouble
with the NIS part. Maybe someone more knowledgeable could write the NIS
function.

Basically we have to reduce each of the functions to a simple nsdispatch 
call and then implement the real functions... Here's an example from
getpwent.c

/* Basically we reduce getpwent to a simple nsdispatch call */

struct passwd *
getpwent()
{
        int r;
        static const ns_dtab dtab[] = {
                NS_FILES_CB(_local_getpw, NULL)
                NS_DNS_CB(_dns_getpw, NULL)
                NS_NIS_CB(_nis_getpw, NULL)
                NS_COMPAT_CB(_compat_getpwent, NULL)
                { 0 }
        };

        r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", compatsrc,
            _PW_KEYBYNUM);
        if (r != NS_SUCCESS)
                return (struct passwd *)NULL;
        return &_pw_passwd;
}

The we have to implement _local_getpw, _dns_getpw, _nis_getpw, 
and _compat_getpwent and make them behave as expected.

NetBSD seems to support having the passwd database on DNS using something
called HESIOD (I hadn't heard about it before). I don't think FreeBSD has
any sort of support for this. 

*Step Three: Implement _ldap_getpw :)

If anyone has any comments, suggestions, etc. I would appreciate it.

Regards,

-Oscar

-- 
For PGP Public Key: finger [EMAIL PROTECTED]
.\"     $NetBSD: nsswitch.conf.5,v 1.14 1999/03/17 20:19:47 garbled Exp $
.\"
.\"  Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
.\"  All rights reserved.
.\" 
.\"  This code is derived from software contributed to The NetBSD Foundation
.\"  by Luke Mewburn.
.\" 
.\"  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.
.\"  3. All advertising materials mentioning features or use of this software
.\"     must display the following acknowledgement:
.\"     This product includes software developed by Luke Mewburn.
.\"  4. The name of the author may not be used to endorse or promote products
.\"     derived from this software without specific prior written permission.
.\"  
.\"  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
.\"
.Dd January 22, 1998
.Dt NSSWITCH.CONF 5
.Os
.Sh NAME
.Nm nsswitch.conf
.Nd name-service switch configuration file
.Sh DESCRIPTION
The
.Nm
file specifies how the
.Xr nsdispatch 3
(name-service switch dispatcher) routines in the C library should operate.
.Pp
The configuration file controls how a process looks up various databases
containing information regarding hosts, users (passwords), groups,
netgroups, etc.
Each database comes from a source (such as local files, DNS, and
.Tn NIS ) ,
and the order to look up the sources is specified in
.Nm nsswitch.conf .
.Pp
Each entry in 
.Nm
consists of a database name, and a space separated list of sources.
Each source can have an optional trailing criterion that determines
whether the next listed source is used, or the search terminates at
the current source.
Each criterion consists of one or more status codes, and actions to
take if that status code occurs.
.Ss Sources
The following sources are implemented:
.Bl -column "compat" -offset indent -compact
.Sy Source      Description
.It files       Local files, such as
.Pa /etc/hosts ,
and
.Pa /etc/passwd .
.It dns Internet Domain Name System.
.Dq hosts
and
.Sq networks
use
.Sy IN
class entries, all other databases use
.Sy HS
class (Hesiod) entries.
.It nis NIS (formerly YP)
.It compat      support
.Sq +/-
in the
.Dq passwd
and
.Dq group
databases.
If this is present, it must be the only source for that entry.
.El
.Ss Databases
The following databases are used by the following C library functions:
.Bl -column "netgroup" -offset indent -compact
.Sy Database    Used by
.It group       
.Xr getpwent 3
.It hosts       
.Xr gethostbyname 3
.It netgroup    
.Xr getnetgrent 3
.It networks    
.Xr getnetbyname 3
.It passwd      
.Xr getpwent 3
.It shells      
.Xr getusershell 3
.El
.Ss Status codes
The following status codes are available:
.Bl -column "tryagain" -offset indent -compact
.Sy Status      Description
.It success     The requested entry was found.
.It notfound    The entry is not present at this source.
.It tryagain    The source is busy, and may respond to retries.
.It unavail     The source is not responding, or entry is corrupt.
.El
.Ss Actions
For each of the status codes, one of two actions is possible:
.Bl -column "continue" -offset indent -compact
.Sy Action      Description
.It continue    Try the next source
.It return      Return with the current result
.El
.Ss Format of file
A
.Tn BNF
description of the syntax of
.Nm
is:
.Bl -column "<criterion>" -offset indent
.It <entry>     ::=
<database> ":" [<source> [<criteria>]]*
.It <criteria>  ::=
"[" <criterion>+ "]"
.It <criterion> ::=
<status> "=" <action>
.It <status>    ::=
"success" | "notfound" | "unavail" | "tryagain"
.It <action>    ::=
"return" | "continue"
.El
.Pp
Each entry starts on a new line in the file.
A
.Sq #
delimits a comment to end of line.
Blank lines are ignored.
A
.Sq \e
at the end of a line escapes the newline, and causes the next line to
be a continuation of the current line.
All entries are case-insensitive.
.Pp
The default criteria is to return on
.Dq success ,
and continue on anything else (i.e,
.Li [success=return notfound=continue unavail=continue tryagain=continue]
).
.Ss Compat mode: +/- syntax
In historical multi-source implementations, the
.Sq +
and
.Sq -
characters are used to specify the importing of user password and
group information from
.Tn NIS .
Although
.Nm
provides alternative methods of accessing distributed sources such as
.Tn NIS ,
specifying a sole source of
.Dq compat
will provide the historical behaviour.
.Pp
An alternative source for the information accessed via
.Sq +/-
can be used by specifying
.Dq passwd_compat: source .
.Dq source
in this case can be
.Sq dns ,
.Sq nis ,
or
any other source except for
.Sq files
and
.Sq compat .
.Ss Notes
Historically, many of the databases had enumeration functions, often of
the form
.Fn getXXXent .
These made sense when the databases were in local files, but don't make
sense or have lesser relevance when there are possibly multiple sources,
each of an unknown size.
The interfaces are still provided for compatibility, but the source
may not be able to provide complete entries, or duplicate entries may
be retrieved if multiple sources that contain similar information are
specified.
.Pp
To ensure compatibility with previous and current implementations, the
.Dq compat
source must appear alone for a given database.
.Ss Default source lists
If, for any reason,
.Nm nsswitch.conf
doesn't exist, or it has missing or corrupt entries,
.Xr nsdispatch 3
will default to an entry of
.Dq files
for the requested database.
Exceptions are:
.Bl -column passwd_compat "dns files" -offset indent
.Sy Database    Default source list
.It group       compat
.It group_compat        nis
.It hosts       dns files
.It netgroup    files [notfound=return] nis
.It passwd      compat
.It passwd_compat       nis
.El
.Sh FILES
.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/nsswitch.conf
The file
.Nm
resides in
.Pa /etc .
.El
.Sh EXAMPLES
To lookup hosts in
.Pa /etc/hosts
and then from the DNS, and lookup user information from
.Tn NIS
then files, use:
.Bl -column "passwd:" -offset indent
.It hosts:      files dns
.It passwd:     nis [notfound=return] files
.It group:      nis [notfound=return] files
.El
.Pp
The criteria
.Dq [notfound=return]
sets a policy of "if the user is notfound in nis, don't try files."
This treats nis as the authoritive source of information, except
when the server is down.
.Sh SEE ALSO
.Xr nsdispatch 3 ,
.Xr resolv.conf 5 ,
.Xr named 8 ,
.Xr ypbind 8
.Sh HISTORY
The
.Nm
file format first appeared in
.Nx 1.4 .
.Sh AUTHORS
Luke Mewburn
.Aq [EMAIL PROTECTED]
wrote this freely distributable name-service switch implementation,
using ideas from the
.Tn ULTRIX
.Xr svc.conf 5
and
.Tn Solaris
.Xr nsswitch.conf 4
manual pages.
/*      $NetBSD: nsswitch.h,v 1.6 1999/01/26 01:04:07 lukem Exp $       */

/*-
 * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Luke Mewburn.
 *
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *        This product includes software developed by the NetBSD
 *        Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
 */

#ifndef _NSSWITCH_H
#define _NSSWITCH_H     1

#include <sys/types.h>

#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#ifndef _PATH_NS_CONF
#define _PATH_NS_CONF   "/etc/nsswitch.conf"
#endif

#define NS_CONTINUE     0
#define NS_RETURN       1

#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_STATUSMASK   0x000000ff      /* bitmask to get the status flags */

/*
 * currently implemented sources
 */
#define NSSRC_FILES     "files"         /* local files */
#define NSSRC_DNS       "dns"           /* DNS; IN for hosts, HS for others */
#define NSSRC_NIS       "nis"           /* YP/NIS */
#define NSSRC_COMPAT    "compat"        /* passwd,group in YP compat mode */

/*
 * currently implemented databases
 */
#define NSDB_HOSTS              "hosts"
#define NSDB_GROUP              "group"
#define NSDB_GROUP_COMPAT       "group_compat"
#define NSDB_NETGROUP           "netgroup"
#define NSDB_NETWORKS           "networks"
#define NSDB_PASSWD             "passwd"
#define NSDB_PASSWD_COMPAT      "passwd_compat"
#define NSDB_SHELLS             "shells"

/*
 * suggested databases to implement
 */
#define NSDB_ALIASES            "aliases"
#define NSDB_AUTH               "auth"
#define NSDB_AUTOMOUNT          "automount"
#define NSDB_BOOTPARAMS         "bootparams"
#define NSDB_ETHERS             "ethers"
#define NSDB_EXPORTS            "exports"
#define NSDB_NETMASKS           "netmasks"
#define NSDB_PHONES             "phones"
#define NSDB_PRINTCAP           "printcap"
#define NSDB_PROTOCOLS          "protocols"
#define NSDB_REMOTE             "remote"
#define NSDB_RPC                "rpc"
#define NSDB_SENDMAILVARS       "sendmailvars"
#define NSDB_SERVICES           "services"
#define NSDB_TERMCAP            "termcap"
#define NSDB_TTYS               "ttys"

/*
 * ns_dtab - `nsswitch dispatch table'
 * contains an entry for each source and the appropriate function to call
 */
typedef struct {
        const char       *src;
        int             (*callback)(void *retval, void *cb_data, va_list ap);
        void             *cb_data;
} ns_dtab;

/*
 * macros to help build an ns_dtab[]
 */
#define NS_FILES_CB(F,C)        { NSSRC_FILES,  F,      C },
#define NS_COMPAT_CB(F,C)       { NSSRC_COMPAT, F,      C },
 
#ifdef HESIOD
#   define NS_DNS_CB(F,C)       { NSSRC_DNS,    F,      C },
#else
#   define NS_DNS_CB(F,C)
#endif

#ifdef YP
#   define NS_NIS_CB(F,C)       { NSSRC_NIS,    F,      C },
#else
#   define NS_NIS_CB(F,C)
#endif

/*
 * ns_src - `nsswitch source'
 * used by the nsparser routines to store a mapping between a source
 * and its dispatch control flags for a given database.
 */
typedef struct {
        const char      *name;
        u_int32_t        flags;
} ns_src;


/*
 * default sourcelist (if nsswitch.conf is missing, corrupt,
 * or the requested database doesn't have an entry.
 */
extern const ns_src __nsdefaultsrc[];


#ifdef _NS_PRIVATE

/*
 * private data structures for back-end nsswitch implementation
 */

/*
 * ns_dbt - `nsswitch database thang'
 * 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 {
        const char      *name;          /* name of database */
        ns_src          *srclist;       /* list of sources */
        int              srclistsize;   /* size of srclist */
} ns_dbt;

#endif /* _NS_PRIVATE */


#include <sys/cdefs.h>

__BEGIN_DECLS
extern  int     nsdispatch      __P((void *, const ns_dtab [], const char *,
                                    const char *, const ns_src [], ...));

#ifdef _NS_PRIVATE
extern  void             _nsdbtaddsrc __P((ns_dbt *, const ns_src *));
extern  void             _nsdbtdump __P((const ns_dbt *));
extern  const ns_dbt    *_nsdbtget __P((const char *));
extern  void             _nsdbtput __P((const ns_dbt *));
extern  void             _nsyyerror __P((const char *));
extern  int              _nsyylex __P((void));
extern  int              _nsyylineno;
#endif /* _NS_PRIVATE */

__END_DECLS

#endif /* !_NSSWITCH_H */
diff -ruN libc.orig/net/Makefile.inc libc/net/Makefile.inc
--- libc.orig/net/Makefile.inc  Thu Jul 29 10:52:31 1999
+++ libc/net/Makefile.inc       Tue Aug  3 08:28:28 1999
@@ -13,18 +13,31 @@
        inet_netof.c inet_network.c inet_ntoa.c inet_ntop.c \
        inet_pton.c linkaddr.c map_v4v6.c ns_addr.c ns_name.c ns_netint.c \
        ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
+       nsdispatch.c nslexer.l nsparser.y \
        rcmd.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 send.c
 # not supported: iso_addr.c 
 
+CLEANFILES+= ${.CURDIR}/net/nsparser.c ${.CURDIR}/net/nsparser.h
+
+YFLAGS+= -d -p_nsyy
+LFLAGS+= -P_nsyy -o/dev/stdout
+
+nsparser.h: nsparser.y
+       ${YACC} ${YFLAGS} -o ${.CURDIR}/net/nsparser.c ${.CURDIR}/net/nsparser.y
+
+nslexer.c: nslexer.l nsparser.h
+       ${LEX} ${LFLAGS} ${.CURDIR}/net/nslexer.l | sed -e 
+'/YY_BUF_SIZE/s/16384/1024/' > ${.TARGET}
+
+
 # machine-dependent net sources
 .include "${.CURDIR}/../libc/${MACHINE_ARCH}/net/Makefile.inc"
 
 .if ${LIB} == "c"
 MAN3+= addr2ascii.3 byteorder.3 ethers.3 gethostbyname.3 \
        getnetent.3 getprotoent.3 getservent.3 \
-       inet.3 linkaddr.3 rcmd.3 resolver.3
+       nsdispatch.3 inet.3 linkaddr.3 rcmd.3 resolver.3
 # not installed: iso_addr.3 ns.3
 
 MLINKS+=addr2ascii.3 ascii2addr.3
@@ -52,4 +65,5 @@
 MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \
        resolver.3 res_mkquery.3 resolver.3 res_query.3 \
        resolver.3 res_search.3 resolver.3 res_send.3
+MLINKS+=nsdispatch.3
 .endif
diff -ruN libc.orig/net/nsdispatch.3 libc/net/nsdispatch.3
--- libc.orig/net/nsdispatch.3  Wed Dec 31 18:00:00 1969
+++ libc/net/nsdispatch.3       Mon Aug  2 10:45:24 1999
@@ -0,0 +1,225 @@
+.\"    $NetBSD: nsdispatch.3,v 1.8 1999/03/22 19:44:53 garbled Exp $
+.\"
+.\" Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"        This product includes software developed by the NetBSD
+.\"        Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd January 19, 1999
+.Dt NSDISPATCH 3
+.Os
+.Sh NAME
+.Nm nsdispatch
+.Nd name-service switch dispatcher routine
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <nsswitch.h>
+.Ft int
+.Fo nsdispatch
+.Fa "void *retval"
+.Fa "const ns_dtab dtab[]"
+.Fa "const char *database"
+.Fa "const char *method"
+.Fa "const ns_src defaults[]"
+.Fa "..."
+.Fc
+.Sh DESCRIPTION
+The
+.Fn nsdispatch
+function invokes the callback functions specified in 
+.Va dtab
+in the order given in
+.Pa /etc/nsswitch.conf
+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 )
+.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;
+} ns_dtab;
+.Ed
+.Pp
+.Bd -ragged -offset indent
+For each source type that is implemented, an entry 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 arbritrary data to the callback function.
+The last entry in
+.Va dtab
+should contain
+.Dv NULL
+values for
+.Va src , 
+.Va cb ,
+and
+.Va cb_data .
+.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.
+.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
+.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;
+} 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
+.Va flags
+set to the relevant flags
+(usually 
+.Dv NS_SUCCESS ;
+refer to
+.Sx Callback return values
+for more information).
+The last entry in
+.Va defaults
+should have
+.Va src
+set to
+.Dv NULL
+and
+.Va flags
+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
+.Sq files
+for use by callers which don't require complicated default rules.
+.Ed
+.Pp
+.Va Sq ...
+are optional extra arguments, which
+are passed to the appropriate callback function as a variable argument
+list of the type
+.Va va_list .
+.Ss Valid source types
+Whilst there is support for arbitrary sources, the following
+#defines for commonly implementated sources are available:
+.Bl -column NS_COMPAT COMPAT -offset indent
+.Sy #define    value
+.It NSSRC_FILES        "files"
+.It NSSRC_DNS  "dns"
+.It NSSRC_NIS  "nis"
+.It NSSRC_COMPAT       "compat"
+.El
+.Pp
+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
+.Sy "Return value"     Status code
+.It NS_SUCCESS success
+.It NS_NOTFOUND        notfound
+.It NS_UNAVAIL unavail
+.It NS_TRYAGAIN        tryagain
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of what each status code is.
+.Pp
+.Nm
+returns the value of the callback that caused the dispatcher to finish,
+or NS_NOTFOUND otherwise.
+.Sh SEE ALSO
+.Xr hesiod 3 ,
+.Xr stdarg 3 ,
+.Xr ypclnt 3 ,
+.Xr nsswitch.conf 5
+.Sh HISTORY
+The
+.Nm
+routines first appeared in
+.Nx 1.4 .
+.Sh AUTHORS
+Luke Mewburn
+.Aq [EMAIL PROTECTED]
+wrote this freely distributable name-service switch implementation,
+using ideas from the
+.Tn ULTRIX
+.Xr svc.conf 5
+and
+.Tn Solaris
+.Xr nsswitch.conf 4
+manual pages.
+.Sh BUGS
+The
+.Nm
+routines are 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 .
diff -ruN libc.orig/net/nsdispatch.c libc/net/nsdispatch.c
--- libc.orig/net/nsdispatch.c  Wed Dec 31 18:00:00 1969
+++ libc/net/nsdispatch.c       Mon Aug  2 10:52:34 1999
@@ -0,0 +1,274 @@
+/*     $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $     */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __weak_alias
+__weak_alias(nsdispatch,_nsdispatch);
+#endif
+
+
+/*
+ * default sourcelist: `files'
+ */
+const ns_src __nsdefaultsrc[] = {
+       { NSSRC_FILES, NS_SUCCESS },
+       { 0 },
+};
+
+
+static int                      _nsmapsize = 0;
+static ns_dbt                  *_nsmap = NULL;
+
+/*
+ * size of dynamic array chunk for _nsmap and _nsmap[x].srclist
+ */
+#define NSELEMSPERCHUNK                8
+
+
+int    _nscmp __P((const void *, const void *));
+
+
+int
+_nscmp(a, b)
+       const void *a;
+       const void *b;
+{
+       return (strcasecmp(((const ns_dbt *)a)->name,
+           ((const ns_dbt *)b)->name));
+}
+
+
+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");
+       }
+       memmove(&dbt->srclist[dbt->srclistsize++], src, sizeof(ns_src));
+}
+
+
+void
+_nsdbtdump(dbt)
+       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++) {
+               printf(" %s", dbt->srclist[i].name);
+               if (!(dbt->srclist[i].flags &
+                   (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
+                   (dbt->srclist[i].flags & NS_SUCCESS))
+                       continue;
+               printf(" [");
+               if (!(dbt->srclist[i].flags & NS_SUCCESS))
+                       printf(" SUCCESS=continue");
+               if (dbt->srclist[i].flags & NS_UNAVAIL)
+                       printf(" UNAVAIL=return");
+               if (dbt->srclist[i].flags & NS_NOTFOUND)
+                       printf(" NOTFOUND=return");
+               if (dbt->srclist[i].flags & NS_TRYAGAIN)
+                       printf(" TRYAGAIN=return");
+               printf(" ]");
+       }
+       printf("\n");
+}
+
+
+const ns_dbt *
+_nsdbtget(name)
+       const char      *name;
+{
+       static  time_t   confmod;
+
+       struct stat      statbuf;
+       ns_dbt           dbt;
+
+       extern  FILE    *_nsyyin;
+       extern  int      _nsyyparse __P((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));
+}
+
+
+void
+_nsdbtput(dbt)
+       const ns_dbt *dbt;
+{
+       int     i;
+
+       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));
+                       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));
+}
+
+
+int
+#if __STDC__
+nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
+           const char *method, const ns_src defaults[], ...)
+#else
+nsdispatch(retval, disp_tab, database, method, defaults, va_alist)
+       void            *retval;
+       const ns_dtab    disp_tab[];
+       const char      *database;
+       const char      *method;
+       const ns_src     defaults[];
+       va_dcl
+#endif
+{
+       va_list          ap;
+       int              i, curdisp, result;
+       const ns_dbt    *dbt;
+       const ns_src    *srclist;
+       int              srclistsize;
+
+       dbt = _nsdbtget(database);
+       if (dbt != NULL) {
+               srclist = dbt->srclist;
+               srclistsize = dbt->srclistsize;
+       } else {
+               srclist = defaults;
+               srclistsize = 0;
+               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) {
+#if __STDC__
+                       va_start(ap, defaults);
+#else
+                       va_start(ap);
+#endif
+                       result = disp_tab[curdisp].callback(retval,
+                           disp_tab[curdisp].cb_data, ap);
+                       va_end(ap);
+                       if (result & srclist[i].flags) {
+                               break;
+                       }
+               }
+       }
+       return (result ? result : NS_NOTFOUND);
+}
diff -ruN libc.orig/net/nslexer.l libc/net/nslexer.l
--- libc.orig/net/nslexer.l     Wed Dec 31 18:00:00 1969
+++ libc/net/nslexer.l  Mon Aug  2 10:45:24 1999
@@ -0,0 +1,115 @@
+%{
+/*     $NetBSD: nslexer.l,v 1.3 1999/01/25 00:16:17 lukem Exp $        */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: nslexer.l,v 1.3 1999/01/25 00:16:17 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <err.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <string.h>
+
+#include "nsparser.h"
+
+#define YY_NO_UNPUT
+
+%}
+
+%option yylineno
+
+BLANK          [ \t]
+CR             \n
+STRING         [a-zA-Z][a-zA-Z0-9_]*
+
+%%
+
+{BLANK}+       ;                       /* skip whitespace */
+
+#.*            ;                       /* skip comments */
+
+\\{CR}         ;                       /* allow continuation */
+
+{CR}           return NL;
+
+[sS][uU][cC][cC][eE][sS][sS]           return SUCCESS;
+[uU][nN][aA][vV][aA][iI][lL]           return UNAVAIL;
+[nN][oO][tT][fF][oO][uU][nN][dD]       return NOTFOUND;
+[tT][rR][yY][aA][gG][aA][iI][nN]       return TRYAGAIN;
+
+[rR][eE][tT][uU][rR][nN]               return RETURN;
+[cC][oO][nN][tT][iI][nN][uU][eE]       return CONTINUE;
+
+{STRING}       {
+                       char *p;
+                       int i;
+
+                       if ((p = strdup(yytext)) == NULL)
+                               err(1, "nsdispatch: memory allocation failure");
+
+                       for (i = 0; i < strlen(p); i++) {
+                               if (isupper((unsigned char)p[i]))
+                                       p[i] = tolower((unsigned char)p[i]);
+                       }
+                       _nsyylval.str = p;
+                       return STRING;
+               }
+
+[:=\[\]]       return yytext[0];
+
+.              ;       /* ignore all else */
+
+%%
+
+#undef _nsyywrap
+int
+_nsyywrap()
+{
+       return 1;
+} /* _nsyywrap */
+
+void
+_nsyyerror(msg)
+       const char *msg;
+{
+
+        warnx("%s line %d: %s at '%s'", _PATH_NS_CONF, yylineno, msg, yytext);
+} /* _nsyyerror */
diff -ruN libc.orig/net/nsparser.y libc/net/nsparser.y
--- libc.orig/net/nsparser.y    Wed Dec 31 18:00:00 1969
+++ libc/net/nsparser.y Mon Aug  2 10:45:24 1999
@@ -0,0 +1,174 @@
+%{
+/*     $NetBSD: nsparser.y,v 1.3 1999/01/25 00:16:18 lukem Exp $       */
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: nsparser.y,v 1.3 1999/01/25 00:16:18 lukem Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <err.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static void    _nsaddsrctomap __P((const char *));
+
+static ns_dbt          curdbt;
+static ns_src          cursrc;
+%}
+
+%union {
+       char *str;
+       int   mapval;
+}
+
+%token NL
+%token SUCCESS UNAVAIL NOTFOUND TRYAGAIN
+%token RETURN CONTINUE
+%token <str> STRING
+
+%type  <mapval> Status Action
+
+%%
+
+File
+       :       /* empty */
+       | Lines
+       ;
+
+Lines
+       : Entry
+       | Lines Entry
+       ;
+
+Entry
+       : NL
+       | Database ':' NL
+       | Database ':' Srclist NL
+               {
+                       _nsdbtput(&curdbt);
+               }
+       ;
+
+Database
+       : STRING
+               {
+                       curdbt.name = yylval.str;
+                       curdbt.srclist = NULL;
+                       curdbt.srclistsize = 0;
+               }
+       ;
+
+Srclist
+       : Item
+       | Srclist Item
+       ;
+
+Item
+       : STRING
+               {
+                       cursrc.flags = NS_SUCCESS;
+                       _nsaddsrctomap($1);
+               }
+       | STRING '[' { cursrc.flags = NS_SUCCESS; } Criteria ']'
+               {
+                       _nsaddsrctomap($1);
+               }
+       ;
+
+Criteria
+       : Criterion
+       | Criteria Criterion
+       ;
+
+Criterion
+       : Status '=' Action
+               {
+                       if ($3)         /* if action == RETURN set RETURN bit */
+                               cursrc.flags |= $1;  
+                       else            /* else unset it */
+                               cursrc.flags &= ~$1;
+               }
+       ;
+
+Status
+       : SUCCESS       { $$ = NS_SUCCESS; }
+       | UNAVAIL       { $$ = NS_UNAVAIL; }
+       | NOTFOUND      { $$ = NS_NOTFOUND; }
+       | TRYAGAIN      { $$ = NS_TRYAGAIN; }
+       ;
+
+Action
+       : RETURN        { $$ = 1L; }
+       | CONTINUE      { $$ = 0L; }
+       ;
+
+%%
+
+static void
+_nsaddsrctomap(elem)
+       const char *elem;
+{
+       int             i, lineno;
+       extern int      _nsyylineno;
+       extern char *   _nsyytext;
+
+       lineno = _nsyylineno - (*_nsyytext == '\n' ? 1 : 0);
+       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",
+                           _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'",
+                           _PATH_NS_CONF, lineno, elem);
+                       return;
+               }
+       }
+       cursrc.name = elem;
+       _nsdbtaddsrc(&curdbt, &cursrc);
+}

Reply via email to