summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/Makefile2
-rw-r--r--etc/host.conf7
-rw-r--r--etc/hosts2
-rw-r--r--etc/network.subr29
-rw-r--r--etc/rc.d/netoptions29
-rw-r--r--etc/rc.d/network129
-rw-r--r--etc/rc.d/network229
-rw-r--r--etc/rc.d/network329
-rw-r--r--etc/rc.d/routing29
-rw-r--r--etc/rc.network29
-rw-r--r--include/Makefile3
-rw-r--r--include/hesiod.h98
-rw-r--r--include/netdb.h10
-rw-r--r--include/nsswitch.h188
-rw-r--r--lib/libc/Makefile.inc3
-rw-r--r--lib/libc/gen/Makefile.inc2
-rw-r--r--lib/libc/gen/getgrent.336
-rw-r--r--lib/libc/gen/getgrent.c903
-rw-r--r--lib/libc/gen/getpwent.332
-rw-r--r--lib/libc/gen/getpwent.c1665
-rw-r--r--lib/libc/gen/getusershell.326
-rw-r--r--lib/libc/gen/getusershell.c249
-rw-r--r--lib/libc/gen/pw_scan.c56
-rw-r--r--lib/libc/gen/pw_scan.h5
-rw-r--r--lib/libc/net/Makefile.inc28
-rw-r--r--lib/libc/net/getaddrinfo.34
-rw-r--r--lib/libc/net/getaddrinfo.c486
-rw-r--r--lib/libc/net/gethostbydns.c65
-rw-r--r--lib/libc/net/gethostbyht.c29
-rw-r--r--lib/libc/net/gethostbyname.317
-rw-r--r--lib/libc/net/gethostbynis.c62
-rw-r--r--lib/libc/net/gethostnamadr.c166
-rw-r--r--lib/libc/net/getipnodebyname.35
-rw-r--r--lib/libc/net/getnameinfo.34
-rw-r--r--lib/libc/net/getnetbydns.c41
-rw-r--r--lib/libc/net/getnetbyht.c27
-rw-r--r--lib/libc/net/getnetbynis.c50
-rw-r--r--lib/libc/net/getnetent.320
-rw-r--r--lib/libc/net/getnetnamadr.c174
-rw-r--r--lib/libc/net/hesiod.3136
-rw-r--r--lib/libc/net/hesiod.c572
-rw-r--r--lib/libc/net/name6.c264
-rw-r--r--lib/libc/net/nsdispatch.3231
-rw-r--r--lib/libc/net/nsdispatch.c270
-rw-r--r--lib/libc/net/nslexer.l116
-rw-r--r--lib/libc/net/nsparser.y175
-rw-r--r--release/sysinstall/installUpgrade.c2
-rw-r--r--release/texts/UPGRADE.TXT21
-rw-r--r--sbin/dhclient/Makefile2
-rw-r--r--share/examples/etc/README.examples2
-rw-r--r--share/man/man4/yp.410
-rw-r--r--share/man/man5/Makefile9
-rw-r--r--share/man/man5/group.536
-rw-r--r--share/man/man5/hesiod.conf.553
-rw-r--r--share/man/man5/hosts.54
-rw-r--r--share/man/man5/nsswitch.conf.5266
-rw-r--r--share/man/man5/passwd.5826
-rw-r--r--share/man/man8/yp.810
-rw-r--r--usr.bin/chpass/Makefile5
-rw-r--r--usr.bin/chpass/chpass.c2
-rw-r--r--usr.bin/chpass/edit.c2
-rw-r--r--usr.bin/hesinfo/Makefile5
-rw-r--r--usr.bin/hesinfo/hesinfo.1226
-rw-r--r--usr.bin/hesinfo/hesinfo.c116
-rw-r--r--usr.sbin/pwd_mkdb/Makefile4
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.c174
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.h40
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c2
-rw-r--r--usr.sbin/rarpd/rarpd.82
-rw-r--r--usr.sbin/sysinstall/installUpgrade.c2
-rw-r--r--usr.sbin/ypserv/ypserv.84
71 files changed, 5404 insertions, 2853 deletions
diff --git a/etc/Makefile b/etc/Makefile
index 3c6bd20..333a324 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -6,7 +6,7 @@ SUBDIR= sendmail
BIN1= amd.map apmd.conf auth.conf \
crontab csh.cshrc csh.login csh.logout \
dhclient.conf dm.conf fbtab ftpusers gettytab group \
- hosts hosts.allow host.conf hosts.equiv hosts.lpd \
+ hosts hosts.allow hosts.equiv hosts.lpd \
inetd.conf login.access login.conf \
motd modems networks newsyslog.conf \
pam.conf phones pim6dd.conf pim6sd.conf \
diff --git a/etc/host.conf b/etc/host.conf
deleted file mode 100644
index f6d2875..0000000
--- a/etc/host.conf
+++ /dev/null
@@ -1,7 +0,0 @@
-# $FreeBSD$
-# First try the /etc/hosts file
-hosts
-# Now try the nameserver next.
-bind
-# If you have YP/NIS configured, uncomment the next line
-# nis
diff --git a/etc/hosts b/etc/hosts
index 3cc2fbd..57b516f 100644
--- a/etc/hosts
+++ b/etc/hosts
@@ -4,7 +4,7 @@
# This file should contain the addresses and aliases
# for local hosts that share this file.
# In the presence of the domain name service or NIS, this file may
-# not be consulted at all; see /etc/host.conf for the resolution order.
+# not be consulted at all; see /etc/nsswitch.conf for the resolution order.
#
#
::1 localhost localhost.my.domain myname.my.domain
diff --git a/etc/network.subr b/etc/network.subr
index 51e02cd..168f3bd 100644
--- a/etc/network.subr
+++ b/etc/network.subr
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/etc/rc.d/netoptions b/etc/rc.d/netoptions
index 51e02cd..168f3bd 100644
--- a/etc/rc.d/netoptions
+++ b/etc/rc.d/netoptions
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/etc/rc.d/network1 b/etc/rc.d/network1
index 51e02cd..168f3bd 100644
--- a/etc/rc.d/network1
+++ b/etc/rc.d/network1
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/etc/rc.d/network2 b/etc/rc.d/network2
index 51e02cd..168f3bd 100644
--- a/etc/rc.d/network2
+++ b/etc/rc.d/network2
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/etc/rc.d/network3 b/etc/rc.d/network3
index 51e02cd..168f3bd 100644
--- a/etc/rc.d/network3
+++ b/etc/rc.d/network3
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/etc/rc.d/routing b/etc/rc.d/routing
index 51e02cd..168f3bd 100644
--- a/etc/rc.d/routing
+++ b/etc/rc.d/routing
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/etc/rc.network b/etc/rc.network
index 51e02cd..168f3bd 100644
--- a/etc/rc.network
+++ b/etc/rc.network
@@ -13,6 +13,18 @@
network_pass1() {
echo -n 'Doing initial network setup:'
+ # Convert host.conf to nsswitch.conf if necessary
+ if [ -f "/etc/host.conf" ]; then
+ echo ""
+ echo "Warning: /etc/host.conf is no longer used"
+ if [ -f "/etc/nsswitch.conf" ]; then
+ echo " /etc/nsswitch.conf will be used instead"
+ else
+ echo " /etc/nsswitch.conf will be created for you"
+ convert_host_conf /etc/host.conf /etc/nsswitch.conf
+ fi
+ fi
+
# Set the host name if it is not already set
#
if [ -z "`hostname -s`" ]; then
@@ -681,3 +693,20 @@ network_pass4() {
echo '.'
network_pass4_done=YES
}
+
+convert_host_conf() {
+ host_conf=$1; shift;
+ nsswitch_conf=$1; shift;
+ awk ' \
+ /^[:blank:]*#/ { next } \
+ /(hosts|local|file)/ { nsswitch[c] = "files"; c++; next } \
+ /(dns|bind)/ { nsswitch[c] = "dns"; c++; next } \
+ /nis/ { nsswitch[c] = "nis"; c++; next } \
+ { printf "Warning: unrecognized line [%s]", $0 > "/dev/stderr" } \
+ END { \
+ printf "hosts: "; \
+ for (i in nsswitch) printf "%s ", nsswitch[i]; \
+ printf "\n"; \
+ }' < $host_conf > $nsswitch_conf
+}
+
diff --git a/include/Makefile b/include/Makefile
index 0494fe0..51d909e 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -10,7 +10,8 @@ CLEANFILES= osreldate.h version vers.c
SUBDIR= rpcsvc
FILES= a.out.h ar.h assert.h bitstring.h ctype.h db.h dirent.h disktab.h \
dlfcn.h elf.h err.h fnmatch.h fstab.h \
- fts.h glob.h grp.h strhash.h histedit.h ieeefp.h ifaddrs.h iso646.h \
+ fts.h glob.h grp.h strhash.h \
+ hesiod.h histedit.h ieeefp.h ifaddrs.h iso646.h \
libgen.h limits.h link.h locale.h malloc.h memory.h mpool.h \
ndbm.h netdb.h nl_types.h nlist.h objformat.h \
paths.h pthread.h pthread_np.h pwd.h \
diff --git a/include/hesiod.h b/include/hesiod.h
new file mode 100644
index 0000000..e2a608f
--- /dev/null
+++ b/include/hesiod.h
@@ -0,0 +1,98 @@
+/* $NetBSD: hesiod.h,v 1.3 1999/01/24 23:53:18 lukem Exp $ */
+/* $FreeBSD$ */
+
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef _HESIOD_H_
+#define _HESIOD_H_
+
+ /* Application-visible indication that we have the new interfaces */
+
+#define HESIOD_INTERFACES
+
+ /* Configuration information. */
+
+#ifndef _PATH_HESIOD_CONF /* Configuration file. */
+#define _PATH_HESIOD_CONF "/etc/hesiod.conf"
+#endif
+
+#define DEF_RHS "" /* Defaults if HESIOD_CONF */
+#define DEF_LHS "" /* file is not present. */
+
+ /* Error codes (for backwards compatibility) */
+
+#define HES_ER_UNINIT -1 /* uninitialized */
+#define HES_ER_OK 0 /* no error */
+#define HES_ER_NOTFOUND 1 /* Hesiod name not found by server */
+#define HES_ER_CONFIG 2 /* local problem (no config file?) */
+#define HES_ER_NET 3 /* network problem */
+
+ /* Declaration of routines */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int hesiod_init __P((void **));
+char **hesiod_resolve __P((void *, const char *, const char *));
+void hesiod_free_list __P((void *, char **));
+char *hesiod_to_bind __P((void *, const char *, const char *));
+void hesiod_end __P((void *));
+
+ /* backwards compatibility */
+int hes_init __P((void));
+char *hes_to_bind __P((const char *, const char *));
+char **hes_resolve __P((const char *, const char *));
+int hes_error __P((void));
+void hes_free __P((char **));
+__END_DECLS
+
+#endif /* ! _HESIOD_H_ */
diff --git a/include/netdb.h b/include/netdb.h
index 7d43899..4f34173 100644
--- a/include/netdb.h
+++ b/include/netdb.h
@@ -240,18 +240,8 @@ void _setnethtent __P((int));
void _endnethtent __P((void));
void _setnetdnsent __P((int));
void _endnetdnsent __P((void));
-struct hostent * _gethostbyhtname __P((const char *, int));
-struct hostent * _gethostbydnsname __P((const char *, int));
struct hostent * _gethostbynisname __P((const char *, int));
-struct hostent * _gethostbyhtaddr __P((const char *, int, int));
-struct hostent * _gethostbydnsaddr __P((const char *, int, int));
struct hostent * _gethostbynisaddr __P((const char *, int, int));
-struct netent * _getnetbyhtname __P((const char *));
-struct netent * _getnetbydnsname __P((const char *));
-struct netent * _getnetbynisname __P((const char *));
-struct netent * _getnetbyhtaddr __P((unsigned long, int));
-struct netent * _getnetbydnsaddr __P((unsigned long, int));
-struct netent * _getnetbynisaddr __P((unsigned long, int));
void _map_v4v6_address __P((const char *src, char *dst));
void _map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len));
__END_DECLS
diff --git a/include/nsswitch.h b/include/nsswitch.h
new file mode 100644
index 0000000..ee9f89a
--- /dev/null
+++ b/include/nsswitch.h
@@ -0,0 +1,188 @@
+/* $NetBSD: nsswitch.h,v 1.6 1999/01/26 01:04:07 lukem Exp $ */
+/* $FreeBSD$ */
+
+/*-
+ * 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 --git a/lib/libc/Makefile.inc b/lib/libc/Makefile.inc
index 318ca70..2994f0e 100644
--- a/lib/libc/Makefile.inc
+++ b/lib/libc/Makefile.inc
@@ -39,6 +39,9 @@ NOASM=
CFLAGS+= -DYP
.include "${.CURDIR}/../libc/yp/Makefile.inc"
.endif
+.if !defined(NO_HESIOD_LIBC)
+CFLAGS+= -DHESIOD
+.endif
# If there are no machine dependent sources, append all the
# machine-independent sources:
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 9d5452a..c63edcd 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -19,7 +19,7 @@ SRCS+= _rand48.c _spinlock_stub.c alarm.c arc4random.c assert.c \
lockf.c lrand48.c mrand48.c msgctl.c \
msgget.c msgrcv.c msgsnd.c nice.c \
nlist.c nrand48.c ntp_gettime.c opendir.c \
- pause.c popen.c psignal.c pwcache.c raise.c readdir.c rewinddir.c \
+ pause.c popen.c psignal.c pw_scan.c pwcache.c raise.c readdir.c rewinddir.c \
posixshm.c \
scandir.c seed48.c seekdir.c semconfig.c semctl.c semget.c semop.c \
setdomainname.c sethostname.c setjmperr.c setmode.c setproctitle.c \
diff --git a/lib/libc/gen/getgrent.3 b/lib/libc/gen/getgrent.3
index bb3f560..d070d8c 100644
--- a/lib/libc/gen/getgrent.3
+++ b/lib/libc/gen/getgrent.3
@@ -125,25 +125,6 @@ The
.Fn endgrent
function
closes any open files.
-.Sh YP/NIS INTERACTION
-When the
-.Xr yp 4
-group database is enabled, the
-.Fn getgrnam
-and
-.Fn getgrgid
-functions use the YP maps
-.Dq Li group.byname
-and
-.Dq Li group.bygid ,
-respectively, if the requested group is not found in the local
-.Pa /etc/group
-file. The
-.Fn getgrent
-function will step through the YP map
-.Dq Li group.byname
-if the entire map is enabled as described in
-.Xr group 5 .
.Sh RETURN VALUES
The functions
.Fn getgrent ,
@@ -171,7 +152,8 @@ group database file
.Sh SEE ALSO
.Xr getpwent 3 ,
.Xr yp 4 ,
-.Xr group 5
+.Xr group 5 ,
+.Xr nsswitch.conf 5
.Sh HISTORY
The functions
.Fn endgrent ,
@@ -206,3 +188,17 @@ a pointer to that object.
Subsequent calls to
the same function
will modify the same object.
+.Pp
+The functions
+.Fn getgrent ,
+.Fn endgrent ,
+.Fn setgroupent ,
+and
+.Fn setgrent
+are fairly useless in a networked environment and should be
+avoided, if possible.
+.Fn getgrent
+makes no attempt to suppress duplicate information if multiple
+sources are specified in
+.Xr nsswitch.conf 5 .
+
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
index 5b5c9da..1f98864 100644
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -1,6 +1,9 @@
+/* $NetBSD: getgrent.c,v 1.34.2.1 1999/04/27 14:10:58 perry Exp $ */
+
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,76 +34,95 @@
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94";
+static char rcsid[] =
+ "$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <nsswitch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <grp.h>
+#include <syslog.h>
-static FILE *_gr_fp;
-static struct group _gr_group;
-static int _gr_stayopen;
-static int grscan(), start_gr();
+#ifdef HESIOD
+#include <hesiod.h>
+#include <arpa/nameser.h>
+#endif
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
-static int _gr_stepping_yp;
-static int _gr_yp_enabled;
-static int _getypgroup(struct group *, const char *, char *);
-static int _nextypgroup(struct group *);
#endif
+#if defined(YP) || defined(HESIOD)
+#define _GROUP_COMPAT
+#endif
+
+static FILE *_gr_fp;
+static struct group _gr_group;
+static int _gr_stayopen;
+static int _gr_filesdone;
+
+static void grcleanup __P((void));
+static int grscan __P((int, gid_t, const char *));
+static char *getline __P((void));
+static int copyline __P((const char*));
+static int matchline __P((int, gid_t, const char *));
+static int start_gr __P((void));
+
+
+
+
/* initial size for malloc and increase steps for realloc */
#define MAXGRP 64
#define MAXLINELENGTH 256
-static char **members; /* list of group members */
-static int maxgrp; /* current length of **mebers */
-static char *line; /* temp buffer for group line */
-static int maxlinelength; /* current length of *line */
+#ifdef HESIOD
+#if MAXLINELENGTH < NS_MAXLABEL + 1
+#error "MAXLINELENGTH must be at least NS_MAXLABEL + 1"
+#endif
+#endif
-/*
- * Lines longer than MAXLINELENGTHLIMIT will be count as an error.
+static char **members; /* list of group members */
+static int maxgrp; /* current length of **members */
+static char *line; /* buffer for group line */
+static int maxlinelength; /* current length of *line */
+
+/*
+ * Lines longer than MAXLINELENGTHLIMIT will be counted as an error.
* <= 0 disable check for maximum line length
* 256K is enough for 64,000 uids
*/
#define MAXLINELENGTHLIMIT (256 * 1024)
-#define GROUP_IGNORE_COMMENTS 1 /* allow comments in /etc/group */
-
-struct group *
-getgrent()
-{
- if (!_gr_fp && !start_gr()) {
- return NULL;
- }
#ifdef YP
- if (_gr_stepping_yp) {
- if (_nextypgroup(&_gr_group))
- return(&_gr_group);
- }
-tryagain:
+static char *__ypcurrent, *__ypdomain;
+static int __ypcurrentlen;
+static int _gr_ypdone;
#endif
- if (!grscan(0, 0, NULL))
- return(NULL);
-#ifdef YP
- if(_gr_group.gr_name[0] == '+' && _gr_group.gr_name[1]) {
- _getypgroup(&_gr_group, &_gr_group.gr_name[1],
- "group.byname");
- } else if(_gr_group.gr_name[0] == '+') {
- if (!_nextypgroup(&_gr_group))
- goto tryagain;
- else
- return(&_gr_group);
- }
+#ifdef HESIOD
+static int _gr_hesnum;
+#endif
+
+#ifdef _GROUP_COMPAT
+enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME };
+static enum _grmode __grmode;
#endif
- return(&_gr_group);
+
+struct group *
+getgrent()
+{
+ if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL))
+ return (NULL);
+ return &_gr_group;
}
struct group *
@@ -110,106 +132,71 @@ getgrnam(name)
int rval;
if (!start_gr())
- return(NULL);
-#ifdef YP
- tryagain:
-#endif
+ return NULL;
rval = grscan(1, 0, name);
-#ifdef YP
- if(rval == -1 && (_gr_yp_enabled < 0 || (_gr_yp_enabled &&
- _gr_group.gr_name[0] == '+'))) {
- if (!(rval = _getypgroup(&_gr_group, name, "group.byname")))
- goto tryagain;
- }
-#endif
if (!_gr_stayopen)
endgrent();
- return(rval ? &_gr_group : NULL);
+ return (rval) ? &_gr_group : NULL;
}
struct group *
-#ifdef __STDC__
-getgrgid(gid_t gid)
-#else
getgrgid(gid)
gid_t gid;
-#endif
{
int rval;
if (!start_gr())
- return(NULL);
-#ifdef YP
- tryagain:
-#endif
+ return NULL;
rval = grscan(1, gid, NULL);
-#ifdef YP
- if(rval == -1 && _gr_yp_enabled) {
- char buf[16];
- snprintf(buf, sizeof buf, "%d", (unsigned)gid);
- if (!(rval = _getypgroup(&_gr_group, buf, "group.bygid")))
- goto tryagain;
- }
-#endif
if (!_gr_stayopen)
endgrent();
- return(rval ? &_gr_group : NULL);
+ return (rval) ? &_gr_group : NULL;
}
-static int
-start_gr()
+void
+grcleanup()
{
- if (_gr_fp) {
- rewind(_gr_fp);
- return(1);
- }
- _gr_fp = fopen(_PATH_GROUP, "r");
- if(!_gr_fp) return 0;
+ _gr_filesdone = 0;
#ifdef YP
- /*
- * This is a disgusting hack, used to determine when YP is enabled.
- * This would be easier if we had a group database to go along with
- * the password database.
- */
- {
- char *line;
- size_t linelen;
- _gr_yp_enabled = 0;
- while((line = fgetln(_gr_fp, &linelen)) != NULL) {
- if(line[0] == '+') {
- if(line[1] && line[1] != ':' && !_gr_yp_enabled) {
- _gr_yp_enabled = 1;
- } else {
- _gr_yp_enabled = -1;
- break;
- }
- }
- }
- rewind(_gr_fp);
- }
+ if (__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ _gr_ypdone = 0;
+#endif
+#ifdef HESIOD
+ _gr_hesnum = 0;
+#endif
+#ifdef _GROUP_COMPAT
+ __grmode = GRMODE_NONE;
#endif
+}
+static int
+start_gr()
+{
+ grcleanup();
if (maxlinelength == 0) {
- if ((line = (char *)malloc(sizeof(char) *
- MAXLINELENGTH)) == NULL)
- return(0);
- maxlinelength += MAXLINELENGTH;
+ if ((line = (char *)malloc(MAXLINELENGTH)) == NULL)
+ return 0;
+ maxlinelength = MAXLINELENGTH;
}
-
if (maxgrp == 0) {
- if ((members = (char **)malloc(sizeof(char **) *
+ if ((members = (char **) malloc(sizeof(char**) *
MAXGRP)) == NULL)
- return(0);
- maxgrp += MAXGRP;
+ return 0;
+ maxgrp = MAXGRP;
}
-
- return 1;
+ if (_gr_fp) {
+ rewind(_gr_fp);
+ return 1;
+ }
+ return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
}
int
-setgrent()
+setgrent(void)
{
- return(setgroupent(0));
+ return setgroupent(0);
}
int
@@ -217,337 +204,503 @@ setgroupent(stayopen)
int stayopen;
{
if (!start_gr())
- return(0);
+ return 0;
_gr_stayopen = stayopen;
-#ifdef YP
- _gr_stepping_yp = 0;
-#endif
- return(1);
+ return 1;
}
void
endgrent()
{
-#ifdef YP
- _gr_stepping_yp = 0;
-#endif
+ grcleanup();
if (_gr_fp) {
(void)fclose(_gr_fp);
_gr_fp = NULL;
}
}
+
+static int _local_grscan __P((void *, void *, va_list));
+
+/*ARGSUSED*/
static int
-grscan(search, gid, name)
- register int search, gid;
- register char *name;
+_local_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- register char *cp, **m;
- char *bp;
-
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
-#ifdef YP
- int _ypfound;
-#endif
+ if (_gr_filesdone)
+ return NS_NOTFOUND;
for (;;) {
-#ifdef YP
- _ypfound = 0;
-#endif
- if (fgets(line, maxlinelength, _gr_fp) == NULL)
- return(0);
-
- if (!index(line, '\n')) {
- do {
- if (feof(_gr_fp))
- return(0);
-
- /* don't allocate infinite memory */
- if (MAXLINELENGTHLIMIT > 0 &&
- maxlinelength >= MAXLINELENGTHLIMIT)
- return(0);
-
- if ((line = (char *)reallocf(line,
- sizeof(char) *
- (maxlinelength + MAXLINELENGTH))) == NULL)
- return(0);
-
- if (fgets(line + maxlinelength - 1,
- MAXLINELENGTH + 1, _gr_fp) == NULL)
- return(0);
-
- maxlinelength += MAXLINELENGTH;
- } while (!index(line + maxlinelength -
- MAXLINELENGTH - 1, '\n'));
+ if (getline() == NULL) {
+ if (!search)
+ _gr_filesdone = 1;
+ return NS_NOTFOUND;
}
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
+ }
+ /* NOTREACHED */
+}
-#ifdef GROUP_IGNORE_COMMENTS
- /*
- * Ignore comments: ^[ \t]*#
- */
- for (cp = line; *cp != '\0'; cp++)
- if (*cp != ' ' && *cp != '\t')
- break;
- if (*cp == '#' || *cp == '\0')
- continue;
-#endif
+#ifdef HESIOD
+static int _dns_grscan __P((void *, void *, va_list));
- bp = line;
+/*ARGSUSED*/
+static int
+_dns_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
- if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL)
- break;
-#ifdef YP
- /*
- * XXX We need to be careful to avoid proceeding
- * past this point under certain circumstances or
- * we risk dereferencing null pointers down below.
- */
- if (_gr_group.gr_name[0] == '+') {
- if (strlen(_gr_group.gr_name) == 1) {
- switch(search) {
- case 0:
- return(1);
- case 1:
- return(-1);
- default:
- return(0);
- }
- } else {
- cp = &_gr_group.gr_name[1];
- if (search && name != NULL)
- if (strcmp(cp, name))
- continue;
- if (!_getypgroup(&_gr_group, cp,
- "group.byname"))
- continue;
- if (search && name == NULL)
- if (gid != _gr_group.gr_gid)
- continue;
- /* We're going to override -- tell the world. */
- _ypfound++;
- }
+ char **hp;
+ void *context;
+ int r;
+ size_t sz;
+
+ r = NS_UNAVAIL;
+ if (!search && _gr_hesnum == -1)
+ return NS_NOTFOUND;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ for (;;) {
+ if (search) {
+ if (name)
+ strlcpy(line, name, maxlinelength);
+ else
+ snprintf(line, maxlinelength, "%u",
+ (unsigned int)gid);
+ } else {
+ snprintf(line, maxlinelength, "group-%u", _gr_hesnum);
+ _gr_hesnum++;
}
-#else
- if (_gr_group.gr_name[0] == '+')
- continue;
-#endif /* YP */
- if (search && name) {
- if(strcmp(_gr_group.gr_name, name)) {
- continue;
+
+ hp = hesiod_resolve(context, line, "group");
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ if (!search)
+ _gr_hesnum = -1;
+ r = NS_NOTFOUND;
}
+ break;
}
-#ifdef YP
- if ((cp = strsep(&bp, ":\n")) == NULL)
- if (_ypfound)
- return(1);
- else
- break;
- if (strlen(cp) || !_ypfound)
- _gr_group.gr_passwd = cp;
-#else
- if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
+
+ /* only check first elem */
+ if (copyline(hp[0]) == 0)
+ return NS_UNAVAIL;
+ hesiod_free_list(context, hp);
+ if (matchline(search, gid, name)) {
+ r = NS_SUCCESS;
break;
-#endif
- if (!(cp = strsep(&bp, ":\n")))
-#ifdef YP
- if (_ypfound)
- return(1);
- else
-#endif
- continue;
-#ifdef YP
- /*
- * Hurm. Should we be doing this? We allow UIDs to
- * be overridden -- what about GIDs?
- */
- if (!_ypfound)
-#endif
- _gr_group.gr_gid = atoi(cp);
- if (search && name == NULL && _gr_group.gr_gid != gid)
- continue;
- cp = NULL;
- if (bp == NULL) /* !!! Must check for this! */
+ } else if (search) {
+ r = NS_NOTFOUND;
break;
+ }
+ }
+ hesiod_end(context);
+ return (r);
+}
+#endif
+
#ifdef YP
- if ((cp = strsep(&bp, ":\n")) == NULL)
+static int _nis_grscan __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_nis_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
+
+ char *key, *data;
+ int keylen, datalen;
+ int r;
+ size_t sz;
+
+ if(__ypdomain == NULL) {
+ switch (yp_get_default_domain(&__ypdomain)) {
+ case 0:
break;
+ case YPERR_RESRC:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ }
- if (!strlen(cp) && _ypfound)
- return(1);
+ if (search) { /* specific group or gid */
+ if (name)
+ strlcpy(line, name, maxlinelength);
else
- members[0] = NULL;
- bp = cp;
- cp = NULL;
-#endif
- for (m = members; ; bp++) {
- if (m == (members + maxgrp - 1)) {
- if ((members = (char **)
- reallocf(members,
- sizeof(char **) *
- (maxgrp + MAXGRP))) == NULL)
- return(0);
- m = members + maxgrp - 1;
- maxgrp += MAXGRP;
- }
- if (*bp == ',') {
- if (cp) {
- *bp = '\0';
- *m++ = cp;
- cp = NULL;
- }
- } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
- if (cp) {
- *bp = '\0';
- *m++ = cp;
- }
+ snprintf(line, maxlinelength, "%u", (unsigned int)gid);
+ data = NULL;
+ r = yp_match(__ypdomain,
+ (name) ? "group.byname" : "group.bygid",
+ line, (int)strlen(line), &data, &datalen);
+ switch (r) {
+ case 0:
+ break;
+ case YPERR_KEY:
+ if (data)
+ free(data);
+ return NS_NOTFOUND;
+ default:
+ if (data)
+ free(data);
+ return NS_UNAVAIL;
+ }
+ data[datalen] = '\0'; /* clear trailing \n */
+ if (copyline(data) == 0)
+ return NS_UNAVAIL;
+ free(data);
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
+ else
+ return NS_NOTFOUND;
+ }
+
+ /* ! search */
+ if (_gr_ypdone)
+ return NS_NOTFOUND;
+ for (;;) {
+ data = NULL;
+ if(__ypcurrent) {
+ key = NULL;
+ r = yp_next(__ypdomain, "group.byname",
+ __ypcurrent, __ypcurrentlen,
+ &key, &keylen, &data, &datalen);
+ free(__ypcurrent);
+ switch (r) {
+ case 0:
break;
- } else if (cp == NULL)
- cp = bp;
-
+ case YPERR_NOMORE:
+ __ypcurrent = NULL;
+ if (key)
+ free(key);
+ if (data)
+ free(data);
+ _gr_ypdone = 1;
+ return NS_NOTFOUND;
+ default:
+ if (key)
+ free(key);
+ if (data)
+ free(data);
+ return NS_UNAVAIL;
+ }
+ __ypcurrent = key;
+ __ypcurrentlen = keylen;
+ } else {
+ if (yp_first(__ypdomain, "group.byname",
+ &__ypcurrent, &__ypcurrentlen,
+ &data, &datalen)) {
+ if (data);
+ free(data);
+ return NS_UNAVAIL;
+ }
}
- _gr_group.gr_mem = members;
- *m = NULL;
- return(1);
+ data[datalen] = '\0'; /* clear trailing \n */
+ if (copyline(data) == 0)
+ return NS_UNAVAIL;
+ free(data);
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
}
/* NOTREACHED */
- return (0);
}
+#endif
-#ifdef YP
+#ifdef _GROUP_COMPAT
+/*
+ * log an error if "files" or "compat" is specified in group_compat database
+ */
+static int _bad_grscan __P((void *, void *, va_list));
+/*ARGSUSED*/
static int
-_gr_breakout_yp(struct group *gr, char *result)
+_bad_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- char *s, *cp;
- char **m;
+ static int warned;
- /*
- * XXX If 's' ends up being a NULL pointer, punt on this group.
- * It means the NIS group entry is badly formatted and should
- * be skipped.
- */
- if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
- gr->gr_name = s;
+ if (!warned) {
+ syslog(LOG_ERR,
+ "nsswitch.conf group_compat database can't use '%s'",
+ (char *)cb_data);
+ }
+ warned = 1;
+ return NS_UNAVAIL;
+}
- if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
- gr->gr_passwd = s;
+/*
+ * when a name lookup in compat mode is required, look it up in group_compat
+ * nsswitch database. only Hesiod and NIS is supported - it doesn't make
+ * sense to lookup compat names from 'files' or 'compat'
+ */
- if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
- gr->gr_gid = atoi(s);
+static int __grscancompat __P((int, gid_t, const char *));
+
+static int
+__grscancompat(search, gid, name)
+ int search;
+ gid_t gid;
+ const char *name;
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_bad_grscan, "files")
+ NS_DNS_CB(_dns_grscan, NULL)
+ NS_NIS_CB(_nis_grscan, NULL)
+ NS_COMPAT_CB(_bad_grscan, "compat")
+ { 0 }
+ };
+ static const ns_src defaultnis[] = {
+ { NSSRC_NIS, NS_SUCCESS },
+ { 0 }
+ };
+
+ return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat",
+ defaultnis, search, gid, name));
+}
+#endif
- if ((s = result) == NULL) return 0;
- cp = 0;
- for (m = members; ; s++) {
- if (m == members + maxgrp - 1) {
- if ((members = (char **)reallocf(members,
- sizeof(char **) * (maxgrp + MAXGRP))) == NULL)
- return(0);
- m = members + maxgrp - 1;
+static int _compat_grscan __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_compat_grscan(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ int search = va_arg(ap, int);
+ gid_t gid = va_arg(ap, gid_t);
+ const char *name = va_arg(ap, const char *);
+
+#ifdef _GROUP_COMPAT
+ static char *grname = NULL;
+#endif
+
+ for (;;) {
+#ifdef _GROUP_COMPAT
+ if(__grmode != GRMODE_NONE) {
+ int r;
+
+ switch(__grmode) {
+ case GRMODE_FULL:
+ r = __grscancompat(search, gid, name);
+ if (r == NS_SUCCESS)
+ return r;
+ __grmode = GRMODE_NONE;
+ break;
+ case GRMODE_NAME:
+ if(grname == (char *)NULL) {
+ __grmode = GRMODE_NONE;
+ break;
+ }
+ r = __grscancompat(1, 0, grname);
+ free(grname);
+ grname = (char *)NULL;
+ if (r != NS_SUCCESS)
+ break;
+ if (!search)
+ return NS_SUCCESS;
+ if (name) {
+ if (! strcmp(_gr_group.gr_name, name))
+ return NS_SUCCESS;
+ } else {
+ if (_gr_group.gr_gid == gid)
+ return NS_SUCCESS;
+ }
+ break;
+ case GRMODE_NONE:
+ abort();
+ }
+ continue;
+ }
+#endif /* _GROUP_COMPAT */
+
+ if (getline() == NULL)
+ return NS_NOTFOUND;
+
+#ifdef _GROUP_COMPAT
+ if (line[0] == '+') {
+ char *tptr, *bp;
+
+ switch(line[1]) {
+ case ':':
+ case '\0':
+ case '\n':
+ __grmode = GRMODE_FULL;
+ break;
+ default:
+ __grmode = GRMODE_NAME;
+ bp = line;
+ tptr = strsep(&bp, ":\n");
+ grname = strdup(tptr + 1);
+ break;
+ }
+ continue;
+ }
+#endif /* _GROUP_COMPAT */
+ if (matchline(search, gid, name))
+ return NS_SUCCESS;
+ }
+ /* NOTREACHED */
+}
+
+static int
+grscan(search, gid, name)
+ int search;
+ gid_t gid;
+ const char *name;
+{
+ int r;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_grscan, NULL)
+ NS_DNS_CB(_dns_grscan, NULL)
+ NS_NIS_CB(_nis_grscan, NULL)
+ NS_COMPAT_CB(_compat_grscan, NULL)
+ { 0 }
+ };
+ static const ns_src compatsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { 0 }
+ };
+
+ r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc,
+ search, gid, name);
+ return (r == NS_SUCCESS) ? 1 : 0;
+}
+
+static int
+matchline(search, gid, name)
+ int search;
+ gid_t gid;
+ const char *name;
+{
+ unsigned long id;
+ char **m;
+ char *cp, *bp, *ep;
+
+ if (line[0] == '+')
+ return 0; /* sanity check to prevent recursion */
+ bp = line;
+ _gr_group.gr_name = strsep(&bp, ":\n");
+ if (search && name && strcmp(_gr_group.gr_name, name))
+ return 0;
+ _gr_group.gr_passwd = strsep(&bp, ":\n");
+ if (!(cp = strsep(&bp, ":\n")))
+ return 0;
+ id = strtoul(cp, &ep, 10);
+ if (*ep != '\0')
+ return 0;
+ _gr_group.gr_gid = (gid_t)id;
+ if (search && name == NULL && _gr_group.gr_gid != gid)
+ return 0;
+ cp = NULL;
+ if (bp == NULL)
+ return 0;
+ for (_gr_group.gr_mem = m = members;; bp++) {
+ if (m == &members[maxgrp - 1]) {
+ members = (char **) reallocf(members, sizeof(char **) *
+ (maxgrp + MAXGRP));
+ if (members == NULL)
+ return 0;
+ _gr_group.gr_mem = members;
+ m = &members[maxgrp - 1];
maxgrp += MAXGRP;
}
- if (*s == ',') {
+ if (*bp == ',') {
if (cp) {
- *s = '\0';
+ *bp = '\0';
*m++ = cp;
cp = NULL;
}
- } else if (*s == '\0' || *s == '\n' || *s == ' ') {
+ } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
if (cp) {
- *s = '\0';
+ *bp = '\0';
*m++ = cp;
}
break;
- } else if (cp == NULL) {
- cp = s;
- }
- }
- _gr_group.gr_mem = members;
+ } else if (cp == NULL)
+ cp = bp;
+ }
*m = NULL;
-
- return 1;
+ return 1;
}
-static char *_gr_yp_domain;
-
-static int
-_getypgroup(struct group *gr, const char *name, char *map)
+static char *
+getline(void)
{
- char *result, *s;
- static char resultbuf[YPMAXRECORD + 2];
- int resultlen;
+ const char *cp;
- if(!_gr_yp_domain) {
- if(yp_get_default_domain(&_gr_yp_domain))
- return 0;
+ tryagain:
+ if (fgets(line, maxlinelength, _gr_fp) == NULL)
+ return NULL;
+ if (index(line, '\n') == NULL) {
+ do {
+ if (feof(_gr_fp))
+ return NULL;
+ if (MAXLINELENGTHLIMIT > 0 &&
+ maxlinelength >= MAXLINELENGTHLIMIT)
+ return NULL;
+ line = (char *)reallocf(line, maxlinelength +
+ MAXLINELENGTH);
+ if (line == NULL)
+ return NULL;
+ if (fgets(line + maxlinelength - 1,
+ MAXLINELENGTH + 1, _gr_fp) == NULL)
+ return NULL;
+ maxlinelength += MAXLINELENGTH;
+ } while (index(line + maxlinelength - MAXLINELENGTH - 1,
+ '\n') == NULL);
}
- if(yp_match(_gr_yp_domain, map, name, strlen(name),
- &result, &resultlen))
- return 0;
-
- s = strchr(result, '\n');
- if(s) *s = '\0';
- if(resultlen >= sizeof resultbuf) return 0;
- strncpy(resultbuf, result, resultlen);
- resultbuf[resultlen] = '\0';
- free(result);
- return(_gr_breakout_yp(gr, resultbuf));
+ /*
+ * Ignore comments: ^[ \t]*#
+ */
+ for (cp = line; *cp != '\0'; cp++)
+ if (*cp != ' ' && *cp != '\t')
+ break;
+ if (*cp == '#' || *cp == '\0')
+ goto tryagain;
+ if (cp != line) /* skip white space at beginning of line */
+ bcopy(cp, line, strlen(cp));
+
+ return line;
}
-
static int
-_nextypgroup(struct group *gr)
+copyline(const char *src)
{
- static char *key;
- static int keylen;
- char *lastkey, *result;
- static char resultbuf[YPMAXRECORD + 2];
- int resultlen;
- int rv;
-
- if(!_gr_yp_domain) {
- if(yp_get_default_domain(&_gr_yp_domain))
- return 0;
- }
+ size_t sz;
- if(!_gr_stepping_yp) {
- if(key) free(key);
- rv = yp_first(_gr_yp_domain, "group.byname",
- &key, &keylen, &result, &resultlen);
- if(rv) {
- return 0;
- }
- _gr_stepping_yp = 1;
- goto unpack;
- } else {
-tryagain:
- lastkey = key;
- rv = yp_next(_gr_yp_domain, "group.byname", key, keylen,
- &key, &keylen, &result, &resultlen);
- free(lastkey);
-unpack:
- if(rv) {
- _gr_stepping_yp = 0;
+ sz = strlen(src);
+ if (sz > maxlinelength - 1) {
+ sz = ((sz/MAXLINELENGTH)+1) * MAXLINELENGTH;
+ if ((line = (char *) reallocf(line, sz)) == NULL)
return 0;
- }
-
- if(resultlen > sizeof(resultbuf)) {
- free(result);
- goto tryagain;
- }
-
- strncpy(resultbuf, result, resultlen);
- resultbuf[resultlen] = '\0';
- free(result);
- if((result = strchr(resultbuf, '\n')) != NULL)
- *result = '\0';
- if (_gr_breakout_yp(gr, resultbuf))
- return(1);
- else
- goto tryagain;
+ maxlinelength = sz;
}
+ strlcpy(line, src, maxlinelength);
+ return 1;
}
-#endif /* YP */
diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3
index 4084289..b606b44 100644
--- a/lib/libc/gen/getpwent.3
+++ b/lib/libc/gen/getpwent.3
@@ -137,24 +137,6 @@ If the process which calls them has an effective uid of 0, the encrypted
password will be returned, otherwise, the password field of the returned
structure will point to the string
.Ql * .
-.Sh YP/NIS INTERACTION
-When the
-.Xr yp 4
-password database is enabled, the
-.Fn getpwnam
-and
-.Fn getpwuid
-functions use the YP maps
-.Dq Li passwd.byname
-and
-.Dq Li passwd.byuid ,
-respectively, if the requested password entry is not found in the
-local database. The
-.Fn getpwent
-function will step through the YP map
-.Dq Li passwd.byname
-if the entire map is enabled as described in
-.Xr passwd 5 .
.Sh RETURN VALUES
The functions
.Fn getpwent ,
@@ -187,6 +169,7 @@ A Version 7 format password file
.Xr getlogin 2 ,
.Xr getgrent 3 ,
.Xr yp 4 ,
+.Xr nsswitch.conf 5 ,
.Xr passwd 5 ,
.Xr pwd_mkdb 8 ,
.Xr vipw 8
@@ -220,3 +203,16 @@ a pointer to that object.
Subsequent calls to
the same function
will modify the same object.
+.Pp
+The functions
+.Fn getpwent ,
+.Fn endpwent ,
+.Fn setpassent ,
+and
+.Fn setpwent
+are fairly useless in a networked environment and should be
+avoided, if possible.
+.Fn getpwent
+makes no attempt to suppress duplicate information if multiple
+sources are specified in
+.Xr nsswitch.conf 5
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
index 00e6ca3..3c8620e 100644
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -1,6 +1,9 @@
+/* $NetBSD: getpwent.c,v 1.40.2.2 1999/04/27 22:09:45 perry Exp $ */
+
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,15 +32,14 @@
* 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$
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
+static const char *rcsid[] =
+ "$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
-#include <stdio.h>
#include <sys/param.h>
#include <fcntl.h>
#include <db.h>
@@ -49,11 +51,27 @@ static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
#include <stdlib.h>
#include <string.h>
#include <limits.h>
-#include <grp.h>
+#include <nsswitch.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#ifdef YP
+#include <machine/param.h>
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+
+extern void setnetgrent __P((char *));
+extern int getnetgrent __P((char **, char **, char **));
+extern int innetgr __P((const char *, const char *, const char *, const char *));
-extern void setnetgrent __P(( char * ));
-extern int getnetgrent __P(( char **, char **, char ** ));
-extern int innetgr __P(( const char *, const char *, const char *, const char * ));
+#include "pw_scan.h"
+
+#if defined(YP) || defined(HESIOD)
+#define _PASSWD_COMPAT
+#endif
/*
* The lookup techniques and data extraction code here must be kept
@@ -62,799 +80,1096 @@ extern int innetgr __P(( const char *, const char *, const char *, const char *
static struct passwd _pw_passwd; /* password structure */
static DB *_pw_db; /* password database */
-static int _pw_keynum; /* key counter */
+static int _pw_keynum; /* key counter. no more records if -1 */
static int _pw_stayopen; /* keep fd's open */
-#ifdef YP
-#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
-#include <rpcsvc/ypclnt.h>
+static int _pw_flags; /* password flags */
-static struct passwd _pw_copy;
-static DBT empty = { NULL, 0 };
-static DB *_ypcache = (DB *)NULL;
-static int _yp_exclusions = 0;
-static int _yp_enabled = -1;
-static int _pw_stepping_yp; /* set true when stepping thru map */
-static char _ypnam[YPMAXRECORD];
-#define YP_HAVE_MASTER 2
-#define YP_HAVE_ADJUNCT 1
-#define YP_HAVE_NONE 0
-static int _gotmaster;
-static char *_pw_yp_domain;
-static inline int unwind __P(( char * ));
-static void _ypinitdb __P(( void ));
-static int _havemaster __P((char *));
-static int _getyppass __P((struct passwd *, const char *, const char * ));
-static int _nextyppass __P((struct passwd *));
-static inline int lookup __P((const char *));
-static inline void store __P((const char *));
-static inline int ingr __P((const char *, const char*));
-static inline int verf __P((const char *));
-static char * _get_adjunct_pw __P((const char *));
-#endif
-static int __hashpw(DBT *);
-static int __initdb(void);
-
-struct passwd *
-getpwent()
-{
- DBT key;
- char bf[sizeof(_pw_keynum) + 1];
- int rv;
+static int __hashpw __P((DBT *));
+static int __initdb __P((void));
- if (!_pw_db && !__initdb())
- return((struct passwd *)NULL);
+static const ns_src compatsrc[] = {
+ { NSSRC_COMPAT, NS_SUCCESS },
+ { 0 }
+};
#ifdef YP
- if(_pw_stepping_yp) {
- _pw_passwd = _pw_copy;
- if (unwind((char *)&_ypnam))
- return(&_pw_passwd);
- }
+static char *__ypcurrent, *__ypdomain;
+static int __ypcurrentlen;
+static int _pw_ypdone; /* non-zero if no more yp records */
#endif
-tryagain:
- ++_pw_keynum;
- bf[0] = _PW_KEYBYNUM;
- bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
- key.data = (u_char *)bf;
- key.size = sizeof(_pw_keynum) + 1;
- rv = __hashpw(&key);
- if(!rv) return (struct passwd *)NULL;
-#ifdef YP
- if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
- if (_yp_enabled == -1)
- _ypinitdb();
- bzero((char *)&_ypnam, sizeof(_ypnam));
- bcopy(_pw_passwd.pw_name, _ypnam,
- strlen(_pw_passwd.pw_name));
- _pw_copy = _pw_passwd;
- if (unwind((char *)&_ypnam) == 0)
- goto tryagain;
- else
- return(&_pw_passwd);
- }
-#else
- /* Ignore YP password file entries when YP is disabled. */
- if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
- goto tryagain;
- }
+#ifdef HESIOD
+static int _pw_hesnum; /* hes counter. no more records if -1 */
#endif
- return(&_pw_passwd);
-}
-struct passwd *
-getpwnam(name)
+#ifdef _PASSWD_COMPAT
+enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP };
+static enum _pwmode __pwmode;
+
+enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER };
+
+static struct passwd *__pwproto = (struct passwd *)NULL;
+static int __pwproto_flags;
+static char line[1024];
+static long prbuf[1024 / sizeof(long)];
+static DB *__pwexclude = (DB *)NULL;
+
+static int __pwexclude_add __P((const char *));
+static int __pwexclude_is __P((const char *));
+static void __pwproto_set __P((void));
+static int __ypmaptype __P((void));
+static int __pwparse __P((struct passwd *, char *));
+
+ /* macros for deciding which YP maps to use. */
+#define PASSWD_BYNAME (__ypmaptype() == YPMAP_MASTER \
+ ? "master.passwd.byname" : "passwd.byname")
+#define PASSWD_BYUID (__ypmaptype() == YPMAP_MASTER \
+ ? "master.passwd.byuid" : "passwd.byuid")
+
+/*
+ * add a name to the compat mode exclude list
+ */
+static int
+__pwexclude_add(name)
const char *name;
{
DBT key;
- int len, rval;
- char bf[UT_NAMESIZE + 2];
+ DBT data;
- if (!_pw_db && !__initdb())
- return((struct passwd *)NULL);
+ /* initialize the exclusion table if needed. */
+ if(__pwexclude == (DB *)NULL) {
+ __pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
+ if(__pwexclude == (DB *)NULL)
+ return 1;
+ }
- bf[0] = _PW_KEYBYNAME;
- len = strlen(name);
- if (len > UT_NAMESIZE)
- return(NULL);
- bcopy(name, bf + 1, len);
- key.data = (u_char *)bf;
- key.size = len + 1;
- rval = __hashpw(&key);
+ /* set up the key */
+ key.size = strlen(name);
+ /* LINTED key does not get modified */
+ key.data = (char *)name;
-#ifdef YP
- if (!rval) {
- if (_yp_enabled == -1)
- _ypinitdb();
- if (_yp_enabled)
- rval = _getyppass(&_pw_passwd, name, "passwd.byname");
- }
-#endif
- /*
- * Prevent login attempts when YP is not enabled but YP entries
- * are in /etc/master.passwd.
- */
- if (rval && (_pw_passwd.pw_name[0] == '+'||
- _pw_passwd.pw_name[0] == '-')) rval = 0;
+ /* data is nothing. */
+ data.data = NULL;
+ data.size = 0;
- if (!_pw_stayopen)
- endpwent();
- return(rval ? &_pw_passwd : (struct passwd *)NULL);
+ /* store it */
+ if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1)
+ return 1;
+
+ return 0;
}
-struct passwd *
-getpwuid(uid)
- uid_t uid;
+/*
+ * test if a name is on the compat mode exclude list
+ */
+static int
+__pwexclude_is(name)
+ const char *name;
{
DBT key;
- int keyuid, rval;
- char bf[sizeof(keyuid) + 1];
-
- if (!_pw_db && !__initdb())
- return((struct passwd *)NULL);
+ DBT data;
- bf[0] = _PW_KEYBYUID;
- keyuid = uid;
- bcopy(&keyuid, bf + 1, sizeof(keyuid));
- key.data = (u_char *)bf;
- key.size = sizeof(keyuid) + 1;
- rval = __hashpw(&key);
+ if(__pwexclude == (DB *)NULL)
+ return 0; /* nothing excluded */
-#ifdef YP
- if (!rval) {
- if (_yp_enabled == -1)
- _ypinitdb();
- if (_yp_enabled) {
- char ypbuf[16]; /* big enough for 32-bit uids */
- snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
- rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
- }
- }
-#endif
- /*
- * Prevent login attempts when YP is not enabled but YP entries
- * are in /etc/master.passwd.
- */
- if (rval && (_pw_passwd.pw_name[0] == '+'||
- _pw_passwd.pw_name[0] == '-')) rval = 0;
+ /* set up the key */
+ key.size = strlen(name);
+ /* LINTED key does not get modified */
+ key.data = (char *)name;
- if (!_pw_stayopen)
- endpwent();
- return(rval ? &_pw_passwd : (struct passwd *)NULL);
+ if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0)
+ return 1; /* excluded */
+
+ return 0;
}
-int
-setpassent(stayopen)
- int stayopen;
+/*
+ * setup the compat mode prototype template
+ */
+static void
+__pwproto_set()
{
- _pw_keynum = 0;
-#ifdef YP
- _pw_stepping_yp = 0;
- if (stayopen)
- setgroupent(1);
-#endif
- _pw_stayopen = stayopen;
- return(1);
+ char *ptr;
+ struct passwd *pw = &_pw_passwd;
+
+ /* make this the new prototype */
+ ptr = (char *)(void *)prbuf;
+
+ /* first allocate the struct. */
+ __pwproto = (struct passwd *)(void *)ptr;
+ ptr += sizeof(struct passwd);
+
+ /* name */
+ if(pw->pw_name && (pw->pw_name)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1);
+ __pwproto->pw_name = ptr;
+ ptr += (strlen(pw->pw_name) + 1);
+ } else
+ __pwproto->pw_name = (char *)NULL;
+
+ /* password */
+ if(pw->pw_passwd && (pw->pw_passwd)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1);
+ __pwproto->pw_passwd = ptr;
+ ptr += (strlen(pw->pw_passwd) + 1);
+ } else
+ __pwproto->pw_passwd = (char *)NULL;
+
+ /* uid */
+ __pwproto->pw_uid = pw->pw_uid;
+
+ /* gid */
+ __pwproto->pw_gid = pw->pw_gid;
+
+ /* change (ignored anyway) */
+ __pwproto->pw_change = pw->pw_change;
+
+ /* class (ignored anyway) */
+ __pwproto->pw_class = "";
+
+ /* gecos */
+ if(pw->pw_gecos && (pw->pw_gecos)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1);
+ __pwproto->pw_gecos = ptr;
+ ptr += (strlen(pw->pw_gecos) + 1);
+ } else
+ __pwproto->pw_gecos = (char *)NULL;
+
+ /* dir */
+ if(pw->pw_dir && (pw->pw_dir)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1);
+ __pwproto->pw_dir = ptr;
+ ptr += (strlen(pw->pw_dir) + 1);
+ } else
+ __pwproto->pw_dir = (char *)NULL;
+
+ /* shell */
+ if(pw->pw_shell && (pw->pw_shell)[0]) {
+ ptr = (char *)ALIGN((u_long)ptr);
+ memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1);
+ __pwproto->pw_shell = ptr;
+ ptr += (strlen(pw->pw_shell) + 1);
+ } else
+ __pwproto->pw_shell = (char *)NULL;
+
+ /* expire (ignored anyway) */
+ __pwproto->pw_expire = pw->pw_expire;
+
+ /* flags */
+ __pwproto_flags = _pw_flags;
}
-void
-setpwent()
+static int
+__ypmaptype()
{
- (void)setpassent(0);
-}
+ static int maptype = -1;
+ int order, r;
-void
-endpwent()
-{
- _pw_keynum = 0;
-#ifdef YP
- _pw_stepping_yp = 0;
-#endif
- if (_pw_db) {
- (void)(_pw_db->close)(_pw_db);
- _pw_db = (DB *)NULL;
- }
-#ifdef YP
- if (_ypcache) {
- (void)(_ypcache->close)(_ypcache);
- _ypcache = (DB *)NULL;
- _yp_exclusions = 0;
- }
- /* Fix for PR #12008 */
- _yp_enabled = -1;
-#endif
-}
+ if (maptype != -1)
+ return (maptype);
-static int
-__initdb()
-{
- static int warned;
- char *p;
+ maptype = YPMAP_NONE;
+ if (geteuid() != 0)
+ return (maptype);
- p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
- _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
- if (_pw_db)
- return(1);
- if (!warned++)
- syslog(LOG_ERR, "%s: %m", p);
- return(0);
-}
+ if (!__ypdomain) {
+ if( _yp_check(&__ypdomain) == 0)
+ return (maptype);
+ }
-static int
-__hashpw(key)
- DBT *key;
-{
- register char *p, *t;
- static u_int max;
- static char *line;
- DBT data;
+ r = yp_order(__ypdomain, "master.passwd.byname", &order);
+ if (r == 0) {
+ maptype = YPMAP_MASTER;
+ return (maptype);
+ }
- if ((_pw_db->get)(_pw_db, key, &data, 0))
- return(0);
- p = (char *)data.data;
+ /*
+ * NIS+ in YP compat mode doesn't support
+ * YPPROC_ORDER -- no point in continuing.
+ */
+ if (r == YPERR_YPERR)
+ return (maptype);
- /* Increase buffer size for long lines if necessary. */
- if (data.size > max) {
- max = data.size + 1024;
- if (!(line = reallocf(line, max)))
- return(0);
+ /* master.passwd doesn't exist -- try passwd.adjunct */
+ if (r == YPERR_MAP) {
+ r = yp_order(__ypdomain, "passwd.adjunct.byname", &order);
+ if (r == 0)
+ maptype = YPMAP_ADJUNCT;
+ return (maptype);
}
- /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
- t = line;
-#define EXPAND(e) e = t; while ( (*t++ = *p++) );
-#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v
- EXPAND(_pw_passwd.pw_name);
- EXPAND(_pw_passwd.pw_passwd);
- SCALAR(_pw_passwd.pw_uid);
- SCALAR(_pw_passwd.pw_gid);
- SCALAR(_pw_passwd.pw_change);
- EXPAND(_pw_passwd.pw_class);
- EXPAND(_pw_passwd.pw_gecos);
- EXPAND(_pw_passwd.pw_dir);
- EXPAND(_pw_passwd.pw_shell);
- SCALAR(_pw_passwd.pw_expire);
- bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
- p += sizeof _pw_passwd.pw_fields;
- return(1);
+ return (maptype);
}
-#ifdef YP
-
-static void
-_ypinitdb()
+/*
+ * parse a passwd file line (from NIS or HESIOD).
+ * assumed to be `old-style' if maptype != YPMAP_MASTER.
+ */
+static int
+__pwparse(pw, s)
+ struct passwd *pw;
+ char *s;
{
- DBT key, data;
- char buf[] = { _PW_KEYYPENABLED };
- key.data = buf;
- key.size = 1;
- _yp_enabled = 0;
- if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) {
- _yp_enabled = (int)*((char *)data.data) - 2;
- /* Don't even bother with this if we aren't root. */
- if (!geteuid()) {
- if (!_pw_yp_domain)
- if (yp_get_default_domain(&_pw_yp_domain))
- return;
- _gotmaster = _havemaster(_pw_yp_domain);
- } else _gotmaster = YP_HAVE_NONE;
- /*
- * Create a DB hash database in memory. Bet you didn't know you
- * could do a dbopen() with a NULL filename, did you.
- */
- if (_ypcache == (DB *)NULL)
- _ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
+ static char adjunctpw[YPMAXRECORD + 2];
+ int flags, maptype;
+
+ maptype = __ypmaptype();
+ flags = 0;
+ if (maptype == YPMAP_MASTER)
+ flags |= _PWSCAN_MASTER;
+ if (! __pw_scan(s, pw, flags))
+ return 1;
+
+ /* now let the prototype override, if set. */
+ if(__pwproto != (struct passwd *)NULL) {
+#ifdef PW_OVERRIDE_PASSWD
+ if(__pwproto_flags & _PWF_PASSWD)
+ pw->pw_passwd = __pwproto->pw_passwd;
+#endif
+ if(__pwproto_flags & _PWF_UID)
+ pw->pw_uid = __pwproto->pw_uid;
+ if(__pwproto_flags & _PWF_GID)
+ pw->pw_gid = __pwproto->pw_gid;
+ if(__pwproto_flags & _PWF_GECOS)
+ pw->pw_gecos = __pwproto->pw_gecos;
+ if(__pwproto_flags & _PWF_DIR)
+ pw->pw_dir = __pwproto->pw_dir;
+ if(__pwproto_flags & _PWF_SHELL)
+ pw->pw_shell = __pwproto->pw_shell;
}
+ if ((maptype == YPMAP_ADJUNCT) &&
+ (strstr(pw->pw_passwd, "##") != NULL)) {
+ char *data, *bp;
+ int datalen;
+
+ if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name,
+ (int)strlen(pw->pw_name), &data, &datalen) == 0) {
+ if (datalen > sizeof(adjunctpw) - 1)
+ datalen = sizeof(adjunctpw) - 1;
+ strncpy(adjunctpw, data, (size_t)datalen);
+
+ /* skip name to get password */
+ if ((bp = strsep(&data, ":")) != NULL &&
+ (bp = strsep(&data, ":")) != NULL)
+ pw->pw_passwd = bp;
+ }
+ }
+ return 0;
}
+#endif /* _PASSWD_COMPAT */
/*
- * See if a user is in the blackballed list.
+ * local files implementation of getpw*()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
*/
-static inline int
-lookup(name)
- const char *name;
+static int _local_getpw __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_local_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- DBT key;
+ DBT key;
+ char bf[/*CONSTCOND*/ MAX(MAXLOGNAME, sizeof(_pw_keynum)) + 1];
+ uid_t uid;
+ int search, len, rval;
+ const char *name;
- if (!_yp_exclusions)
- return(0);
+ if (!_pw_db && !__initdb())
+ return NS_UNAVAIL;
+
+ search = va_arg(ap, int);
+ bf[0] = search;
+ switch (search) {
+ case _PW_KEYBYNUM:
+ if (_pw_keynum == -1)
+ return NS_NOTFOUND; /* no more local records */
+ ++_pw_keynum;
+ memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
+ key.size = sizeof(_pw_keynum) + 1;
+ break;
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, const char *);
+ len = strlen(name);
+ memmove(bf + 1, name, (size_t)MIN(len, MAXLOGNAME));
+ key.size = len + 1;
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ memmove(bf + 1, &uid, sizeof(len));
+ key.size = sizeof(uid) + 1;
+ break;
+ default:
+ abort();
+ }
- key.data = (char *)name;
- key.size = strlen(name);
+ key.data = (u_char *)bf;
+ rval = __hashpw(&key);
+ if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM)
+ _pw_keynum = -1; /* flag `no more local records' */
- if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
- return(0);
+ if (!_pw_stayopen && (search != _PW_KEYBYNUM)) {
+ (void)(_pw_db->close)(_pw_db);
+ _pw_db = (DB *)NULL;
}
-
- return(1);
+ return (rval);
}
+#ifdef HESIOD
/*
- * Store a blackballed user in an in-core hash database.
+ * hesiod implementation of getpw*()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
*/
-static inline void
-store(key)
- const char *key;
-{
- DBT lkey;
-/*
- if (lookup(key))
- return;
-*/
-
- _yp_exclusions = 1;
+static int _dns_getpw __P((void *, void *, va_list));
- lkey.data = (char *)key;
- lkey.size = strlen(key);
+/*ARGSUSED*/
+static int
+_dns_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ const char *name;
+ uid_t uid;
+ int search;
+
+ const char *map;
+ char **hp;
+ void *context;
+ int r;
+
+ search = va_arg(ap, int);
+ nextdnsbynum:
+ switch (search) {
+ case _PW_KEYBYNUM:
+ if (_pw_hesnum == -1)
+ return NS_NOTFOUND; /* no more hesiod records */
+ snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum);
+ _pw_hesnum++;
+ map = "passwd";
+ break;
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, const char *);
+ strncpy(line, name, sizeof(line));
+ map = "passwd";
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ snprintf(line, sizeof(line), "%u", (unsigned int)uid);
+ map = "uid"; /* XXX this is `passwd' on ultrix */
+ break;
+ default:
+ abort();
+ }
+ line[sizeof(line) - 1] = '\0';
+
+ r = NS_UNAVAIL;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ hp = hesiod_resolve(context, line, map);
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ /* flag `no more hesiod records' */
+ if (search == _PW_KEYBYNUM)
+ _pw_hesnum = -1;
+ r = NS_NOTFOUND;
+ }
+ goto cleanup_dns_getpw;
+ }
- (void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
+ strncpy(line, hp[0], sizeof(line)); /* only check first elem */
+ line[sizeof(line) - 1] = '\0';
+ hesiod_free_list(context, hp);
+ if (__pwparse(&_pw_passwd, line)) {
+ if (search == _PW_KEYBYNUM)
+ goto nextdnsbynum; /* skip dogdy entries */
+ r = NS_UNAVAIL;
+ } else
+ r = NS_SUCCESS;
+ cleanup_dns_getpw:
+ hesiod_end(context);
+ return (r);
}
+#endif
+#ifdef YP
/*
- * Parse the + entries in the password database and do appropriate
- * NIS lookups. While ugly to look at, this is optimized to do only
- * as many lookups as are absolutely necessary in any given case.
- * Basically, the getpwent() function will feed us + and - lines
- * as they appear in the database. For + lines, we do netgroup/group
- * and user lookups to find all usernames that match the rule and
- * extract them from the NIS passwd maps. For - lines, we save the
- * matching names in a database and a) exlude them, and b) make sure
- * we don't consider them when processing other + lines that appear
- * later.
+ * nis implementation of getpw*()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
*/
-static inline int
-unwind(grp)
- char *grp;
+static int _nis_getpw __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_nis_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- char *user, *host, *domain;
- static int latch = 0;
- static struct group *gr = NULL;
- int rv = 0;
-
- if (grp[0] == '+') {
- if (strlen(grp) == 1) {
- return(_nextyppass(&_pw_passwd));
+ const char *name;
+ uid_t uid;
+ int search;
+ char *key, *data;
+ char *map;
+ int keylen, datalen, r, rval;
+
+ if(__ypdomain == NULL) {
+ if(_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+
+ map = PASSWD_BYNAME;
+ search = va_arg(ap, int);
+ switch (search) {
+ case _PW_KEYBYNUM:
+ break;
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, const char *);
+ strncpy(line, name, sizeof(line));
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ snprintf(line, sizeof(line), "%u", (unsigned int)uid);
+ map = PASSWD_BYUID;
+ break;
+ default:
+ abort();
+ }
+ line[sizeof(line) - 1] = '\0';
+ rval = NS_UNAVAIL;
+ if (search != _PW_KEYBYNUM) {
+ data = NULL;
+ r = yp_match(__ypdomain, map, line, (int)strlen(line),
+ &data, &datalen);
+ if (r == YPERR_KEY)
+ rval = NS_NOTFOUND;
+ if (r != 0) {
+ if (data)
+ free(data);
+ return (rval);
}
- if (grp[1] == '@') {
- _pw_stepping_yp = 1;
-grpagain:
- if (gr != NULL) {
- if (*gr->gr_mem != NULL) {
- if (lookup(*gr->gr_mem)) {
- gr->gr_mem++;
- goto grpagain;
- }
- rv = _getyppass(&_pw_passwd,
- *gr->gr_mem,
- "passwd.byname");
- gr->gr_mem++;
- return(rv);
- } else {
- latch = 0;
- _pw_stepping_yp = 0;
- gr = NULL;
- return(0);
- }
- }
- if (!latch) {
- setnetgrent(grp+2);
- latch++;
- }
-again:
- if (getnetgrent(&host, &user, &domain) == 0) {
- if ((gr = getgrnam(grp+2)) != NULL)
- goto grpagain;
- latch = 0;
- _pw_stepping_yp = 0;
- return(0);
- } else {
- if (lookup(user))
- goto again;
- if (_getyppass(&_pw_passwd, user,
- "passwd.byname"))
- return(1);
- else
- goto again;
+ data[datalen] = '\0'; /* clear trailing \n */
+ strncpy(line, data, sizeof(line));
+ line[sizeof(line) - 1] = '\0';
+ free(data);
+ if (__pwparse(&_pw_passwd, line))
+ return NS_UNAVAIL;
+ return NS_SUCCESS;
+ }
+
+ if (_pw_ypdone)
+ return NS_NOTFOUND;
+ for (;;) {
+ data = key = NULL;
+ if (__ypcurrent) {
+ r = yp_next(__ypdomain, map,
+ __ypcurrent, __ypcurrentlen,
+ &key, &keylen, &data, &datalen);
+ free(__ypcurrent);
+ switch (r) {
+ case 0:
+ __ypcurrent = key;
+ __ypcurrentlen = keylen;
+ break;
+ case YPERR_NOMORE:
+ __ypcurrent = NULL;
+ /* flag `no more yp records' */
+ _pw_ypdone = 1;
+ rval = NS_NOTFOUND;
}
} else {
- if (lookup(grp+1))
- return(0);
- return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
+ r = yp_first(__ypdomain, map, &__ypcurrent,
+ &__ypcurrentlen, &data, &datalen);
}
- } else {
- if (grp[1] == '@') {
- setnetgrent(grp+2);
- rv = 0;
- while(getnetgrent(&host, &user, &domain) != 0) {
- store(user);
- rv++;
- }
- if (!rv && (gr = getgrnam(grp+2)) != NULL) {
- while(*gr->gr_mem) {
- store(*gr->gr_mem);
- gr->gr_mem++;
- }
- }
- } else {
- store(grp+1);
+ if (r != 0) {
+ if (key)
+ free(key);
+ if (data)
+ free(data);
+ return (rval);
}
+ data[datalen] = '\0'; /* clear trailing \n */
+ strncpy(line, data, sizeof(line));
+ line[sizeof(line) - 1] = '\0';
+ free(data);
+ if (! __pwparse(&_pw_passwd, line))
+ return NS_SUCCESS;
}
- return(0);
-}
+ /* NOTREACHED */
+} /* _nis_getpw */
+#endif
+#ifdef _PASSWD_COMPAT
/*
- * See if a user is a member of a particular group.
+ * See if the compat token is in the database. Only works if pwd_mkdb knows
+ * about the token.
*/
-static inline int
-ingr(grp, name)
- const char *grp;
- const char *name;
+static int __has_compatpw __P((void));
+
+static int
+__has_compatpw()
{
- register struct group *gr;
+ DBT key, data;
+ DBT pkey, pdata;
+ char bf[MAXLOGNAME];
+ u_char cyp[] = { _PW_KEYYPENABLED };
- if ((gr = getgrnam(grp)) == NULL)
- return(0);
+ /*LINTED*/
+ key.data = cyp;
+ key.size = 1;
- while(*gr->gr_mem) {
- if (!strcmp(*gr->gr_mem, name))
- return(1);
- gr->gr_mem++;
- }
+ /* Pre-token database support. */
+ bf[0] = _PW_KEYBYNAME;
+ bf[1] = '+';
+ pkey.data = (u_char *)bf;
+ pkey.size = 2;
- return(0);
+ if ((_pw_db->get)(_pw_db, &key, &data, 0)
+ && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
+ return 0; /* No compat token */
+ return 1;
}
/*
- * Check a user against the +@netgroup/-@netgroup lines listed in
- * the local password database. Also checks +user/-user lines.
- * If no netgroup exists that matches +@netgroup/-@netgroup,
- * try searching regular groups with the same name.
+ * log an error if "files" or "compat" is specified in passwd_compat database
*/
-static inline int
-verf(name)
- const char *name;
-{
- DBT key;
- char bf[sizeof(_pw_keynum) + 1];
- int keynum = 0;
+static int _bad_getpw __P((void *, void *, va_list));
-again:
- ++keynum;
- bf[0] = _PW_KEYYPBYNUM;
- bcopy((char *)&keynum, bf + 1, sizeof(keynum));
- key.data = (u_char *)bf;
- key.size = sizeof(keynum) + 1;
- if (!__hashpw(&key)) {
- /* Try again using old format */
- bf[0] = _PW_KEYBYNUM;
- bcopy((char *)&keynum, bf + 1, sizeof(keynum));
- key.data = (u_char *)bf;
- if (!__hashpw(&key))
- return(0);
- }
- if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
- goto again;
- if (_pw_passwd.pw_name[0] == '+') {
- if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
- return(1);
- if (_pw_passwd.pw_name[1] == '@') {
- if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
- _pw_yp_domain) ||
- ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
- return(1);
- else
- goto again;
- } else {
- if (!strcmp(name, _pw_passwd.pw_name+1) &&
- !lookup(name))
- return(1);
- else
- goto again;
- }
- }
- if (_pw_passwd.pw_name[0] == '-') {
- /* Note that a minus wildcard is a no-op. */
- if (_pw_passwd.pw_name[1] == '@') {
- if (innetgr(_pw_passwd.pw_name+2, NULL, name,
- _pw_yp_domain) ||
- ingr(_pw_passwd.pw_name+2, name)) {
- store(name);
- return(0);
- } else
- goto again;
- } else {
- if (!strcmp(name, _pw_passwd.pw_name+1)) {
- store(name);
- return(0);
- } else
- goto again;
- }
-
+/*ARGSUSED*/
+static int
+_bad_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ static int warned;
+ if (!warned) {
+ syslog(LOG_ERR,
+ "nsswitch.conf passwd_compat database can't use '%s'",
+ (char *)cb_data);
}
- return(0);
+ warned = 1;
+ return NS_UNAVAIL;
}
-static char *
-_get_adjunct_pw(name)
- const char *name;
-{
- static char adjunctbuf[YPMAXRECORD+2];
- int rval;
- char *result;
- int resultlen;
- char *map = "passwd.adjunct.byname";
- char *s;
-
- if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name),
- &result, &resultlen)))
- return(NULL);
-
- strncpy(adjunctbuf, result, resultlen);
- adjunctbuf[resultlen] = '\0';
- free(result);
- result = (char *)&adjunctbuf;
-
- /* Don't care about the name. */
- if ((s = strsep(&result, ":")) == NULL)
- return (NULL); /* name */
- if ((s = strsep(&result, ":")) == NULL)
- return (NULL); /* password */
+/*
+ * when a name lookup in compat mode is required (e.g., '+name', or a name in
+ * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database.
+ * only Hesiod and NIS is supported - it doesn't make sense to lookup
+ * compat names from 'files' or 'compat'.
+ */
+static int __getpwcompat __P((int, uid_t, const char *));
- return(s);
+static int
+__getpwcompat(type, uid, name)
+ int type;
+ uid_t uid;
+ const char *name;
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_bad_getpw, "files")
+ NS_DNS_CB(_dns_getpw, NULL)
+ NS_NIS_CB(_nis_getpw, NULL)
+ NS_COMPAT_CB(_bad_getpw, "compat")
+ { 0 }
+ };
+ static const ns_src defaultnis[] = {
+ { NSSRC_NIS, NS_SUCCESS },
+ { 0 }
+ };
+
+ switch (type) {
+ case _PW_KEYBYNUM:
+ return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat",
+ defaultnis, type);
+ case _PW_KEYBYNAME:
+ return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat",
+ defaultnis, type, name);
+ case _PW_KEYBYUID:
+ return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat",
+ defaultnis, type, uid);
+ default:
+ abort();
+ /*NOTREACHED*/
+ }
}
+#endif /* _PASSWD_COMPAT */
+
+/*
+ * compat implementation of getpwent()
+ * varargs (ignored):
+ * type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
+ */
+static int _compat_getpwent __P((void *, void *, va_list));
+/*ARGSUSED*/
static int
-_pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master)
+_compat_getpwent(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- char *s, *result;
- static char resbuf[YPMAXRECORD+2];
+ DBT key;
+ int rval;
+ char bf[sizeof(_pw_keynum) + 1];
+#ifdef _PASSWD_COMPAT
+ static char *name = NULL;
+ char *user, *host, *dom;
+ int has_compatpw;
+#endif
- /*
- * Be triple, ultra super-duper paranoid: reject entries
- * that start with a + or -. yp_mkdb and /var/yp/Makefile
- * are _both_ supposed to strip these out, but you never
- * know.
- */
- if (*res == '+' || *res == '-')
- return 0;
+ if (!_pw_db && !__initdb())
+ return NS_UNAVAIL;
- /*
- * The NIS protocol definition limits the size of an NIS
- * record to YPMAXRECORD bytes. We need to do a copy to
- * a static buffer here since the memory pointed to by
- * res will be free()ed when this function returns.
- */
- strncpy((char *)&resbuf, res, resultlen);
- resbuf[resultlen] = '\0';
- result = (char *)&resbuf;
+#ifdef _PASSWD_COMPAT
+ has_compatpw = __has_compatpw();
- /*
- * XXX Sanity check: make sure all fields are valid (no NULLs).
- * If we find a badly formatted entry, we punt.
- */
- if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
- /*
- * We don't care what pw_fields says: we _always_ want the
- * username returned to us by NIS.
- */
- pw->pw_name = s;
- pw->pw_fields |= _PWF_NAME;
-
- if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
- if(!(pw->pw_fields & _PWF_PASSWD)) {
- /* SunOS passwd.adjunct hack */
- if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) {
- char *realpw;
- realpw = _get_adjunct_pw(pw->pw_name);
- if (realpw == NULL)
- pw->pw_passwd = s;
- else
- pw->pw_passwd = realpw;
- } else {
- pw->pw_passwd = s;
+again:
+ if (has_compatpw && (__pwmode != PWMODE_NONE)) {
+ int r;
+
+ switch (__pwmode) {
+ case PWMODE_FULL:
+ r = __getpwcompat(_PW_KEYBYNUM, 0, NULL);
+ if (r == NS_SUCCESS)
+ return r;
+ __pwmode = PWMODE_NONE;
+ break;
+
+ case PWMODE_NETGRP:
+ r = getnetgrent(&host, &user, &dom);
+ if (r == 0) { /* end of group */
+ endnetgrent();
+ __pwmode = PWMODE_NONE;
+ break;
+ }
+ if (!user || !*user)
+ break;
+ r = __getpwcompat(_PW_KEYBYNAME, 0, user);
+ if (r == NS_SUCCESS)
+ return r;
+ break;
+
+ case PWMODE_USER:
+ if (name == NULL) {
+ __pwmode = PWMODE_NONE;
+ break;
+ }
+ r = __getpwcompat(_PW_KEYBYNAME, 0, name);
+ free(name);
+ name = NULL;
+ if (r == NS_SUCCESS)
+ return r;
+ break;
+
+ case PWMODE_NONE:
+ abort();
}
- pw->pw_fields |= _PWF_PASSWD;
+ goto again;
}
+#endif
- if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
- if(!(pw->pw_fields & _PWF_UID)) {
- pw->pw_uid = atoi(s);
- pw->pw_fields |= _PWF_UID;
- }
+ if (_pw_keynum == -1)
+ return NS_NOTFOUND; /* no more local records */
+ ++_pw_keynum;
+ bf[0] = _PW_KEYBYNUM;
+ memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum));
+ key.data = (u_char *)bf;
+ key.size = sizeof(_pw_keynum) + 1;
+ rval = __hashpw(&key);
+ if (rval == NS_NOTFOUND)
+ _pw_keynum = -1; /* flag `no more local records' */
+ else if (rval == NS_SUCCESS) {
+#ifdef _PASSWD_COMPAT
+ /* if we don't have YP at all, don't bother. */
+ if (has_compatpw) {
+ if(_pw_passwd.pw_name[0] == '+') {
+ /* set the mode */
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ __pwmode = PWMODE_FULL;
+ break;
+ case '@':
+ __pwmode = PWMODE_NETGRP;
+ setnetgrent(_pw_passwd.pw_name + 2);
+ break;
+ default:
+ __pwmode = PWMODE_USER;
+ name = strdup(_pw_passwd.pw_name + 1);
+ break;
+ }
- if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
- if(!(pw->pw_fields & _PWF_GID)) {
- pw->pw_gid = atoi(s);
- pw->pw_fields |= _PWF_GID;
+ /* save the prototype */
+ __pwproto_set();
+ goto again;
+ } else if(_pw_passwd.pw_name[0] == '-') {
+ /* an attempted exclusion */
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ break;
+ case '@':
+ setnetgrent(_pw_passwd.pw_name + 2);
+ while(getnetgrent(&host, &user, &dom)) {
+ if(user && *user)
+ __pwexclude_add(user);
+ }
+ endnetgrent();
+ break;
+ default:
+ __pwexclude_add(_pw_passwd.pw_name + 1);
+ break;
+ }
+ goto again;
+ }
+ }
+#endif
}
+ return (rval);
+}
- if (master == YP_HAVE_MASTER) {
- if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
- if(!(pw->pw_fields & _PWF_CLASS)) {
- pw->pw_class = s;
- pw->pw_fields |= _PWF_CLASS;
- }
+/*
+ * compat implementation of getpwnam() and getpwuid()
+ * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
+ */
+static int _compat_getpw __P((void *, void *, va_list));
- if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
- if(!(pw->pw_fields & _PWF_CHANGE)) {
- pw->pw_change = atol(s);
- pw->pw_fields |= _PWF_CHANGE;
- }
+static int
+_compat_getpw(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+#ifdef _PASSWD_COMPAT
+ DBT key;
+ int search, rval, r, s, keynum;
+ uid_t uid;
+ char bf[sizeof(keynum) + 1];
+ char *name, *host, *user, *dom;
+#endif
- if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
- if(!(pw->pw_fields & _PWF_EXPIRE)) {
- pw->pw_expire = atol(s);
- pw->pw_fields |= _PWF_EXPIRE;
- }
- }
+ if (!_pw_db && !__initdb())
+ return NS_UNAVAIL;
- if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
- if(!(pw->pw_fields & _PWF_GECOS)) {
- pw->pw_gecos = s;
- pw->pw_fields |= _PWF_GECOS;
+ /*
+ * If there isn't a compat token in the database, use files.
+ */
+#ifdef _PASSWD_COMPAT
+ if (! __has_compatpw())
+#endif
+ return (_local_getpw(rv, cb_data, ap));
+
+#ifdef _PASSWD_COMPAT
+ search = va_arg(ap, int);
+ uid = 0;
+ name = NULL;
+ rval = NS_NOTFOUND;
+ switch (search) {
+ case _PW_KEYBYNAME:
+ name = va_arg(ap, char *);
+ break;
+ case _PW_KEYBYUID:
+ uid = va_arg(ap, uid_t);
+ break;
+ default:
+ abort();
}
- if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
- if(!(pw->pw_fields & _PWF_DIR)) {
- pw->pw_dir = s;
- pw->pw_fields |= _PWF_DIR;
+ for (s = -1, keynum = 1 ; ; keynum++) {
+ bf[0] = _PW_KEYBYNUM;
+ memmove(bf + 1, &keynum, sizeof(keynum));
+ key.data = (u_char *)bf;
+ key.size = sizeof(keynum) + 1;
+ if(__hashpw(&key) != NS_SUCCESS)
+ break;
+ switch(_pw_passwd.pw_name[0]) {
+ case '+':
+ /* save the prototype */
+ __pwproto_set();
+
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ r = __getpwcompat(search, uid, name);
+ if (r != NS_SUCCESS)
+ continue;
+ break;
+ case '@':
+pwnam_netgrp:
+#if 0 /* XXX: is this a hangover from pre-nsswitch? */
+ if(__ypcurrent) {
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ }
+#endif
+ if (s == -1) /* first time */
+ setnetgrent(_pw_passwd.pw_name + 2);
+ s = getnetgrent(&host, &user, &dom);
+ if (s == 0) { /* end of group */
+ endnetgrent();
+ s = -1;
+ continue;
+ }
+ if (!user || !*user)
+ goto pwnam_netgrp;
+
+ r = __getpwcompat(_PW_KEYBYNAME, 0, user);
+
+ if (r == NS_UNAVAIL)
+ return r;
+ if (r == NS_NOTFOUND) {
+ /*
+ * just because this user is bad
+ * it doesn't mean they all are.
+ */
+ goto pwnam_netgrp;
+ }
+ break;
+ default:
+ user = _pw_passwd.pw_name + 1;
+ r = __getpwcompat(_PW_KEYBYNAME, 0, user);
+
+ if (r == NS_UNAVAIL)
+ return r;
+ if (r == NS_NOTFOUND)
+ continue;
+ break;
+ }
+ if(__pwexclude_is(_pw_passwd.pw_name)) {
+ if(s == 1) /* inside netgroup */
+ goto pwnam_netgrp;
+ continue;
+ }
+ break;
+ case '-':
+ /* attempted exclusion */
+ switch(_pw_passwd.pw_name[1]) {
+ case '\0':
+ break;
+ case '@':
+ setnetgrent(_pw_passwd.pw_name + 2);
+ while(getnetgrent(&host, &user, &dom)) {
+ if(user && *user)
+ __pwexclude_add(user);
+ }
+ endnetgrent();
+ break;
+ default:
+ __pwexclude_add(_pw_passwd.pw_name + 1);
+ break;
+ }
+ break;
+ }
+ if ((search == _PW_KEYBYNAME &&
+ strcmp(_pw_passwd.pw_name, name) == 0)
+ || (search == _PW_KEYBYUID && _pw_passwd.pw_uid == uid)) {
+ rval = NS_SUCCESS;
+ break;
+ }
+ if(s == 1) /* inside netgroup */
+ goto pwnam_netgrp;
+ continue;
}
+ __pwproto = (struct passwd *)NULL;
- if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
- if(!(pw->pw_fields & _PWF_SHELL)) {
- pw->pw_shell = s;
- pw->pw_fields |= _PWF_SHELL;
+ if (!_pw_stayopen) {
+ (void)(_pw_db->close)(_pw_db);
+ _pw_db = (DB *)NULL;
}
-
- /* Be consistent. */
- if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
-
- return 1;
+ if(__pwexclude != (DB *)NULL) {
+ (void)(__pwexclude->close)(__pwexclude);
+ __pwexclude = (DB *)NULL;
+ }
+ return rval;
+#endif /* _PASSWD_COMPAT */
}
-static int
-_havemaster(char *_yp_domain)
+struct passwd *
+getpwent()
{
- int order;
- int rval;
+ 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;
+}
- if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order)))
- return(YP_HAVE_MASTER);
+struct passwd *
+getpwnam(name)
+ const char *name;
+{
+ 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_getpw, NULL)
+ { 0 }
+ };
+
+ if (name == NULL || name[0] == '\0')
+ return (struct passwd *)NULL;
+
+ r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", compatsrc,
+ _PW_KEYBYNAME, name);
+ return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
+}
- /*
- * NIS+ in YP compat mode doesn't support
- * YPPROC_ORDER -- no point in continuing.
- */
- if (rval == YPERR_YPERR)
- return(YP_HAVE_NONE);
+struct passwd *
+getpwuid(uid)
+ uid_t uid;
+{
+ 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_getpw, NULL)
+ { 0 }
+ };
+
+ r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", compatsrc,
+ _PW_KEYBYUID, uid);
+ return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
+}
- /* master.passwd doesn't exist -- try passwd.adjunct */
- if (rval == YPERR_MAP) {
- rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order);
- if (!rval)
- return(YP_HAVE_ADJUNCT);
+int
+setpassent(stayopen)
+ int stayopen;
+{
+ _pw_keynum = 0;
+ _pw_stayopen = stayopen;
+#ifdef YP
+ __pwmode = PWMODE_NONE;
+ if(__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ _pw_ypdone = 0;
+#endif
+#ifdef HESIOD
+ _pw_hesnum = 0;
+#endif
+#ifdef _PASSWD_COMPAT
+ if(__pwexclude != (DB *)NULL) {
+ (void)(__pwexclude->close)(__pwexclude);
+ __pwexclude = (DB *)NULL;
}
+ __pwproto = (struct passwd *)NULL;
+#endif
+ return 1;
+}
- return (YP_HAVE_NONE);
+void
+setpwent()
+{
+ (void) setpassent(0);
}
-static int
-_getyppass(struct passwd *pw, const char *name, const char *map)
+void
+endpwent()
{
- char *result, *s;
- int resultlen;
- int rv;
- char mastermap[YPMAXRECORD];
-
- if(!_pw_yp_domain) {
- if(yp_get_default_domain(&_pw_yp_domain))
- return 0;
+ _pw_keynum = 0;
+ if (_pw_db) {
+ (void)(_pw_db->close)(_pw_db);
+ _pw_db = (DB *)NULL;
}
-
- if (_gotmaster == YP_HAVE_MASTER)
- snprintf(mastermap, sizeof(mastermap), "master.%s", map);
- else
- snprintf(mastermap, sizeof(mastermap), "%s", map);
-
- if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
- &result, &resultlen)) {
- if (_gotmaster != YP_HAVE_MASTER)
- return 0;
- snprintf(mastermap, sizeof(mastermap), "%s", map);
- if (yp_match(_pw_yp_domain, (char *)&mastermap,
- name, strlen(name), &result, &resultlen))
- return 0;
- _gotmaster = YP_HAVE_NONE;
+#ifdef _PASSWD_COMPAT
+ __pwmode = PWMODE_NONE;
+#endif
+#ifdef YP
+ if(__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+ _pw_ypdone = 0;
+#endif
+#ifdef HESIOD
+ _pw_hesnum = 0;
+#endif
+#ifdef _PASSWD_COMPAT
+ if(__pwexclude != (DB *)NULL) {
+ (void)(__pwexclude->close)(__pwexclude);
+ __pwexclude = (DB *)NULL;
}
+ __pwproto = (struct passwd *)NULL;
+#endif
+}
- if (!_pw_stepping_yp) {
- s = strchr(result, ':');
- if (s) {
- *s = '\0';
- } else {
- /* Must be a malformed entry if no colons. */
- free(result);
- return(0);
- }
-
- if (!verf(result)) {
- *s = ':';
- free(result);
- return(0);
- }
+static int
+__initdb()
+{
+ static int warned;
+ char *p;
- *s = ':'; /* Put back the colon we previously replaced with a NUL. */
+#ifdef _PASSWD_COMPAT
+ __pwmode = PWMODE_NONE;
+#endif
+ if (geteuid() == 0) {
+ _pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL);
+ if (_pw_db)
+ return(1);
}
-
- rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster);
- free(result);
- return(rv);
+ _pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL);
+ if (_pw_db)
+ return 1;
+ if (!warned)
+ syslog(LOG_ERR, "%s: %m", p);
+ warned = 1;
+ return 0;
}
static int
-_nextyppass(struct passwd *pw)
+__hashpw(key)
+ DBT *key;
{
- static char *key;
- static int keylen;
- char *lastkey, *result, *s;
- int resultlen;
- int rv;
- char *map = "passwd.byname";
-
- if(!_pw_yp_domain) {
- if(yp_get_default_domain(&_pw_yp_domain))
- return 0;
- }
-
- if (_gotmaster == YP_HAVE_MASTER)
- map = "master.passwd.byname";
+ char *p, *t;
+ static u_int max;
+ static char *buf;
+ DBT data;
- if(!_pw_stepping_yp) {
- if(key) free(key);
- rv = yp_first(_pw_yp_domain, map,
- &key, &keylen, &result, &resultlen);
- if(rv) {
- return 0;
- }
- _pw_stepping_yp = 1;
- goto unpack;
- } else {
-tryagain:
- lastkey = key;
- rv = yp_next(_pw_yp_domain, map, key, keylen,
- &key, &keylen, &result, &resultlen);
- free(lastkey);
-unpack:
- if(rv) {
- _pw_stepping_yp = 0;
- return 0;
- }
+ switch ((_pw_db->get)(_pw_db, key, &data, 0)) {
+ case 0:
+ break; /* found */
+ case 1:
+ return NS_NOTFOUND;
+ case -1:
+ return NS_UNAVAIL; /* error in db routines */
+ default:
+ abort();
+ }
- s = strchr(result, ':');
- if (s) {
- *s = '\0';
- } else {
- /* Must be a malformed entry if no colons. */
- free(result);
- goto tryagain;
- }
+ p = (char *)data.data;
+ if (data.size > max && !(buf = realloc(buf, (max += 1024))))
+ return NS_UNAVAIL;
- if (lookup(result)) {
- *s = ':';
- free(result);
- goto tryagain;
- }
+ /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+ t = buf;
+#define EXPAND(e) e = t; while ((*t++ = *p++));
+#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v
+ EXPAND(_pw_passwd.pw_name);
+ EXPAND(_pw_passwd.pw_passwd);
+ SCALAR(_pw_passwd.pw_uid);
+ SCALAR(_pw_passwd.pw_gid);
+ SCALAR(_pw_passwd.pw_change);
+ EXPAND(_pw_passwd.pw_class);
+ EXPAND(_pw_passwd.pw_gecos);
+ EXPAND(_pw_passwd.pw_dir);
+ EXPAND(_pw_passwd.pw_shell);
+ SCALAR(_pw_passwd.pw_expire);
+ SCALAR(_pw_passwd.pw_fields);
- *s = ':'; /* Put back the colon we previously replaced with a NUL. */
- if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) {
- free(result);
- return(1);
- } else {
- free(result);
- goto tryagain;
- }
- }
+ return NS_SUCCESS;
}
-
-#endif /* YP */
diff --git a/lib/libc/gen/getusershell.3 b/lib/libc/gen/getusershell.3
index 068c5d9..d4924fa 100644
--- a/lib/libc/gen/getusershell.3
+++ b/lib/libc/gen/getusershell.3
@@ -1,3 +1,6 @@
+.\" $NetBSD: getusershell.3,v 1.6 1999/03/22 19:44:42 garbled Exp $
+.\" $FreeBSD$
+.\"
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -30,16 +33,15 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)getusershell.3 8.1 (Berkeley) 6/4/93
-.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd January 16, 1999
.Dt GETUSERSHELL 3
-.Os BSD 4.3
+.Os
.Sh NAME
.Nm getusershell ,
.Nm setusershell ,
.Nm endusershell
-.Nd get legal user shells
+.Nd get valid user shells
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -54,18 +56,16 @@
The
.Fn getusershell
function
-returns a pointer to a legal user shell as defined by the
-system manager in the file
-.Pa /etc/shells .
-If
-.Pa /etc/shells
-is unreadable or does not exist,
+returns a pointer to a valid user shell as defined by the
+system manager in the shells database as described in
+.Xr shells 5 .
+If the shells database is not available,
.Fn getusershell
behaves as if
.Pa /bin/sh
and
.Pa /bin/csh
-were listed in the file.
+were listed.
.Pp
The
.Fn getusershell
@@ -86,6 +86,7 @@ The routine
returns a null pointer (0) on
.Dv EOF .
.Sh SEE ALSO
+.Xr nsswitch.conf 5 ,
.Xr shells 5
.Sh HISTORY
The
@@ -96,7 +97,6 @@ function appeared in
The
.Fn getusershell
function leaves its result in an internal static object and returns
-a pointer to that object.
-Subsequent calls to
+a pointer to that object. Subsequent calls to
.Fn getusershell
will modify the same object.
diff --git a/lib/libc/gen/getusershell.c b/lib/libc/gen/getusershell.c
index be1a77a..a852421 100644
--- a/lib/libc/gen/getusershell.c
+++ b/lib/libc/gen/getusershell.c
@@ -1,3 +1,5 @@
+/* $NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $ */
+
/*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
@@ -29,111 +31,248 @@
* 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$
*/
+#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getusershell.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] =
+ "$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/file.h>
-#include <sys/stat.h>
-#include <stdio.h>
+
#include <ctype.h>
+#include <errno.h>
+#include <nsswitch.h>
+#include <paths.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
#include <unistd.h>
-#include <paths.h>
+
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#endif
/*
* Local shells should NOT be added here. They should be added in
* /etc/shells.
*/
-static char *okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
-static char **curshell, **shells, *strings;
-static char **initshells __P((void));
+static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
+static const char *const *curshell;
+static StringList *sl;
+
+static const char *const *initshells __P((void));
/*
- * Get a list of shells from _PATH_SHELLS, if it exists.
+ * Get a list of shells from "shells" nsswitch database
*/
char *
-getusershell()
+getusershell(void)
{
char *ret;
if (curshell == NULL)
curshell = initshells();
- ret = *curshell;
+ /*LINTED*/
+ ret = (char *)*curshell;
if (ret != NULL)
curshell++;
return (ret);
}
void
-endusershell()
+endusershell(void)
{
-
- if (shells != NULL)
- free(shells);
- shells = NULL;
- if (strings != NULL)
- free(strings);
- strings = NULL;
+ if (sl)
+ sl_free(sl, 1);
+ sl = NULL;
curshell = NULL;
}
void
-setusershell()
+setusershell(void)
{
curshell = initshells();
}
-static char **
-initshells()
+
+static int _local_initshells __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_local_initshells(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- register char **sp, *cp;
- register FILE *fp;
- struct stat statb;
-
- if (shells != NULL)
- free(shells);
- shells = NULL;
- if (strings != NULL)
- free(strings);
- strings = NULL;
+ char *sp, *cp;
+ FILE *fp;
+ char line[MAXPATHLEN + 2];
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
- return (okshells);
- if (fstat(fileno(fp), &statb) == -1) {
- (void)fclose(fp);
- return (okshells);
- }
- if ((strings = malloc((u_int)statb.st_size)) == NULL) {
- (void)fclose(fp);
- return (okshells);
- }
- shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
- if (shells == NULL) {
- (void)fclose(fp);
- free(strings);
- strings = NULL;
- return (okshells);
- }
- sp = shells;
- cp = strings;
+ return NS_UNAVAIL;
+
+ sp = cp = line;
while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
while (*cp != '#' && *cp != '/' && *cp != '\0')
cp++;
if (*cp == '#' || *cp == '\0')
continue;
- *sp++ = cp;
- while (!isspace((unsigned char)*cp) && *cp != '#' && *cp != '\0')
+ sp = cp;
+ while (!isspace(*cp) && *cp != '#' && *cp != '\0')
cp++;
*cp++ = '\0';
+ sl_add(sl, strdup(sp));
}
- *sp = NULL;
(void)fclose(fp);
- return (shells);
+ return NS_SUCCESS;
+}
+
+#ifdef HESIOD
+static int _dns_initshells __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_dns_initshells(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ char shellname[] = "shells-XXXXX";
+ int hsindex, hpi, r;
+ char **hp;
+ void *context;
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+ r = NS_UNAVAIL;
+ if (hesiod_init(&context) == -1)
+ return (r);
+
+ for (hsindex = 0; ; hsindex++) {
+ snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
+ hp = hesiod_resolve(context, shellname, "shells");
+ if (hp == NULL) {
+ if (errno == ENOENT) {
+ if (hsindex == 0)
+ r = NS_NOTFOUND;
+ else
+ r = NS_SUCCESS;
+ }
+ break;
+ } else {
+ for (hpi = 0; hp[hpi]; hpi++)
+ sl_add(sl, hp[hpi]);
+ free(hp);
+ }
+ }
+ hesiod_end(context);
+ return (r);
+}
+#endif /* HESIOD */
+
+#ifdef YP
+static int _nis_initshells __P((void *, void *, va_list));
+
+/*ARGSUSED*/
+static int
+_nis_initshells(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ static char *ypdomain;
+
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if (ypdomain == NULL) {
+ switch (yp_get_default_domain(&ypdomain)) {
+ case 0:
+ break;
+ case YPERR_RESRC:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ }
+
+ for (;;) {
+ char *ypcur = NULL;
+ int ypcurlen = 0; /* XXX: GCC */
+ char *key, *data;
+ int keylen, datalen;
+ int r;
+
+ key = data = NULL;
+ if (ypcur) {
+ r = yp_next(ypdomain, "shells", ypcur, ypcurlen,
+ &key, &keylen, &data, &datalen);
+ free(ypcur);
+ switch (r) {
+ case 0:
+ break;
+ case YPERR_NOMORE:
+ free(key);
+ free(data);
+ return NS_SUCCESS;
+ default:
+ free(key);
+ free(data);
+ return NS_UNAVAIL;
+ }
+ ypcur = key;
+ ypcurlen = keylen;
+ } else {
+ if (yp_first(ypdomain, "shells", &ypcur,
+ &ypcurlen, &data, &datalen)) {
+ free(data);
+ return NS_UNAVAIL;
+ }
+ }
+ data[datalen] = '\0'; /* clear trailing \n */
+ sl_add(sl, data);
+ }
+}
+#endif /* YP */
+
+static const char *const *
+initshells()
+{
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_local_initshells, NULL)
+ NS_DNS_CB(_dns_initshells, NULL)
+ NS_NIS_CB(_nis_initshells, NULL)
+ { 0 }
+ };
+ if (sl)
+ sl_free(sl, 1);
+ sl = sl_init();
+
+ if (nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
+ != NS_SUCCESS) {
+ if (sl)
+ sl_free(sl, 1);
+ sl = NULL;
+ return (okshells);
+ }
+ sl_add(sl, NULL);
+
+ return (const char *const *)(sl->sl_str);
}
diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c
index d0fb5f1..3ecb9e0 100644
--- a/lib/libc/gen/pw_scan.c
+++ b/lib/libc/gen/pw_scan.c
@@ -66,12 +66,10 @@ static const char rcsid[] =
* it will be set based on the existance of PW_SCAN_BIG_IDS in the
* environment.
*/
-int pw_big_ids_warning = -1;
+static int pw_big_ids_warning = -1;
int
-pw_scan(bp, pw)
- char *bp;
- struct passwd *pw;
+__pw_scan(char *bp, struct passwd *pw, int flags)
{
uid_t id;
int root;
@@ -97,20 +95,23 @@ pw_scan(bp, pw)
pw->pw_fields |= _PWF_UID;
else {
if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
- warnx("no uid for user %s", pw->pw_name);
+ if (flags & _PWSCAN_WARN)
+ warnx("no uid for user %s", pw->pw_name);
return (0);
}
}
id = strtoul(p, (char **)NULL, 10);
if (errno == ERANGE) {
- warnx("%s > max uid value (%u)", p, ULONG_MAX);
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max uid value (%u)", p, ULONG_MAX);
return (0);
}
if (root && id) {
- warnx("root uid should be 0");
+ if (flags & _PWSCAN_WARN)
+ warnx("root uid should be 0");
return (0);
}
- if (pw_big_ids_warning && id > USHRT_MAX) {
+ if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
/*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
}
@@ -121,28 +122,30 @@ pw_scan(bp, pw)
if(p[0]) pw->pw_fields |= _PWF_GID;
id = strtoul(p, (char **)NULL, 10);
if (errno == ERANGE) {
- warnx("%s > max gid value (%u)", p, ULONG_MAX);
+ if (flags & _PWSCAN_WARN)
+ warnx("%s > max gid value (%u)", p, ULONG_MAX);
return (0);
}
- if (pw_big_ids_warning && id > USHRT_MAX) {
+ if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
warnx("%s > recommended max gid value (%u)", p, USHRT_MAX);
/* return (0); This should not be fatal! */
}
pw->pw_gid = id;
- pw->pw_class = strsep(&bp, ":"); /* class */
- if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
-
- if (!(p = strsep(&bp, ":"))) /* change */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_CHANGE;
- pw->pw_change = atol(p);
-
- if (!(p = strsep(&bp, ":"))) /* expire */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
- pw->pw_expire = atol(p);
-
+ if (flags & _PWSCAN_MASTER ) {
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
+
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_CHANGE;
+ pw->pw_change = atol(p);
+
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
+ pw->pw_expire = atol(p);
+ }
if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */
goto fmt;
if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS;
@@ -158,7 +161,8 @@ pw_scan(bp, pw)
if (root && *p) /* empty == /bin/sh */
for (setusershell();;) {
if (!(sh = getusershell())) {
- warnx("warning, unknown root shell");
+ if (flags & _PWSCAN_WARN)
+ warnx("warning, unknown root shell");
break;
}
if (!strcmp(p, sh))
@@ -167,7 +171,9 @@ pw_scan(bp, pw)
if(p[0]) pw->pw_fields |= _PWF_SHELL;
if ((p = strsep(&bp, ":"))) { /* too many */
-fmt: warnx("corrupted entry");
+fmt:
+ if (flags & _PWSCAN_WARN)
+ warnx("corrupted entry");
return (0);
}
return (1);
diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h
index 2519bd4..3bc6201 100644
--- a/lib/libc/gen/pw_scan.h
+++ b/lib/libc/gen/pw_scan.h
@@ -35,6 +35,7 @@
* $FreeBSD$
*/
-extern int pw_big_ids_warning;
+#define _PWSCAN_MASTER 0x01
+#define _PWSCAN_WARN 0x02
-extern int pw_scan __P((char *, struct passwd *));
+extern int __pw_scan __P((char *, struct passwd *, int));
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index 1d3ab66..3f84d10 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -9,19 +9,32 @@ SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c getaddrinfo.c \
getifaddrs.c getnameinfo.c \
getnetbydns.c getnetbyht.c getnetbynis.c getnetnamadr.c \
getproto.c getprotoent.c getprotoname.c getservbyname.c \
- getservbyport.c getservent.c herror.c inet_addr.c ifname.c \
- inet_lnaof.c \
+ getservbyport.c getservent.c herror.c hesiod.c inet_addr.c \
+ ifname.c inet_lnaof.c \
inet_makeaddr.c inet_net_ntop.c inet_net_pton.c inet_neta.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_addr.c \
ns_name.c ns_netint.c \
- ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
- rcmd.c recv.c res_comp.c res_data.c res_debug.c \
+ ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c \
+ nsdispatch.c nslexer.c nsparser.c \
+ nsap_addr.c 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 rthdr.c send.c vars.c
# not supported: iso_addr.c
-CFLAGS+=-DINET6
+CFLAGS+=-DINET6 -I${.OBJDIR}
+
+YFLAGS+=-p_nsyy
+LFLAGS+=-P_nsyy
+
+CLEANFILES+=nsparser.c nslexer.c nsparser.h
+
+nsparser.h: nsparser.c
+ mv y.tab.h ${.TARGET}
+
+nslexer.c: nslexer.l nsparser.h
+ ${LEX} ${LFLAGS} -o/dev/stdout ${.IMPSRC} | \
+ sed -e '/YY_BUF_SIZE/s/16384/1024/' >${.TARGET}
# machine-dependent net sources
.include "${.CURDIR}/../libc/${MACHINE_ARCH}/net/Makefile.inc"
@@ -29,9 +42,10 @@ CFLAGS+=-DINET6
.if ${LIB} == "c"
MAN3+= addr2ascii.3 byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 \
getifaddrs.3 getipnodebyname.3 \
- getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 if_indextoname.3 \
+ getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 hesiod.3 \
+ if_indextoname.3 \
inet.3 inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
- rcmd.3 resolver.3
+ nsdispatch.3 rcmd.3 resolver.3
# not installed: iso_addr.3 ns.3
MLINKS+=addr2ascii.3 ascii2addr.3
diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3
index 1a0b5f4..deb575f 100644
--- a/lib/libc/net/getaddrinfo.3
+++ b/lib/libc/net/getaddrinfo.3
@@ -496,9 +496,9 @@ freeaddrinfo(res0);
.Ed
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 6d23544..10ddd3a 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD$ */
/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
/*
@@ -103,14 +103,18 @@
#include <stdio.h>
#include <errno.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+
#if defined(__KAME__) && defined(INET6)
# define FAITH
#endif
-#define SUCCESS 0
-#define ANY 0
-#define YES 1
-#define NO 0
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
static const char in_addrany[] = { 0, 0, 0, 0 };
static const char in6_addrany[] = {
@@ -127,7 +131,7 @@ static const struct afd {
int a_socklen;
int a_off;
const char *a_addrany;
- const char *a_loopback;
+ const char *a_loopback;
int a_scoped;
} afdl [] = {
#ifdef INET6
@@ -153,9 +157,9 @@ struct explore {
int e_protocol;
const char *e_protostr;
int e_wild;
-#define WILD_AF(ex) ((ex)->e_wild & 0x01)
-#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
-#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+#define WILD_AF(ex) ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
};
static const struct explore explore[] = {
@@ -177,11 +181,17 @@ static const struct explore explore[] = {
};
#ifdef INET6
-#define PTON_MAX 16
+#define PTON_MAX 16
#else
-#define PTON_MAX 4
+#define PTON_MAX 4
#endif
+static const ns_src default_dns_files[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
+};
+
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
@@ -223,24 +233,22 @@ static int addrconfig __P((struct addrinfo *));
static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
#endif
-static struct addrinfo *getanswer __P((const querybuf *, int, const char *,
- int, const struct addrinfo *));
-static int _dns_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
-static struct addrinfo *_gethtent __P((FILE *fp, const char *,
- const struct addrinfo *));
-static int _files_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
+static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int,
+ const struct addrinfo *));
+static int _dns_getaddrinfo __P((void *, void *, va_list));
+static void _sethtent __P((void));
+static void _endhtent __P((void));
+static struct addrinfo *_gethtent __P((const char *, const struct addrinfo *));
+static int _files_getaddrinfo __P((void *, void *, va_list));
#ifdef YP
-static int _nis_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
+static struct addrinfo *_yphostent __P((char *, const struct addrinfo *));
+static int _yp_getaddrinfo __P((void *, void *, va_list));
#endif
static int res_queryN __P((const char *, struct res_target *));
static int res_searchN __P((const char *, struct res_target *));
static int res_querydomainN __P((const char *, const char *,
- struct res_target *));
-
+ struct res_target *));
static char *ai_errlist[] = {
"Success",
@@ -263,35 +271,9 @@ static char *ai_errlist[] = {
"Unknown error", /* EAI_MAX */
};
-/*
- * Select order host function.
- */
-#define MAXHOSTCONF 4
-
-#ifndef HOSTCONF
-# define HOSTCONF "/etc/host.conf"
-#endif /* !HOSTCONF */
-
-struct _hostconf {
- int (*byname)(const struct addrinfo *, const char *,
- struct addrinfo **);
-};
-
-/* default order */
-static struct _hostconf _hostconf[MAXHOSTCONF] = {
- _dns_getaddrinfo,
- _files_getaddrinfo,
-#ifdef ICMPNL
- NULL,
-#endif /* ICMPNL */
-};
-
-static int _hostconf_init_done;
-static void _hostconf_init(void);
-
/* XXX macros that make external reference is BAD. */
-#define GET_AI(ai, afd, addr) \
+#define GET_AI(ai, afd, addr) \
do { \
/* external reference: pai, error, and label free */ \
(ai) = get_ai(pai, (afd), (addr)); \
@@ -301,7 +283,7 @@ do { \
} \
} while (/*CONSTCOND*/0)
-#define GET_PORT(ai, serv) \
+#define GET_PORT(ai, serv) \
do { \
/* external reference: error and label free */ \
error = get_port((ai), (serv), 0); \
@@ -309,7 +291,7 @@ do { \
goto free; \
} while (/*CONSTCOND*/0)
-#define GET_CANONNAME(ai, str) \
+#define GET_CANONNAME(ai, str) \
do { \
/* external reference: pai, error and label free */ \
error = get_canonname(pai, (ai), (str)); \
@@ -317,7 +299,7 @@ do { \
goto free; \
} while (/*CONSTCOND*/0)
-#define ERR(err) \
+#define ERR(err) \
do { \
/* external reference: error, and label bad */ \
error = (err); \
@@ -325,9 +307,9 @@ do { \
/*NOTREACHED*/ \
} while (/*CONSTCOND*/0)
-#define MATCH_FAMILY(x, y, w) \
+#define MATCH_FAMILY(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
-#define MATCH(x, y, w) \
+#define MATCH(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
char *
@@ -470,7 +452,7 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
- || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
@@ -501,11 +483,9 @@ getaddrinfo(hostname, servname, hints, res)
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
continue;
- if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex)))
+ if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
continue;
- if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex)))
+ if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
continue;
if (pai->ai_family == PF_UNSPEC)
@@ -518,8 +498,7 @@ getaddrinfo(hostname, servname, hints, res)
if (hostname == NULL)
error = explore_null(pai, servname, &cur->ai_next);
else
- error = explore_numeric_scope(pai, hostname, servname,
- &cur->ai_next);
+ error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
if (error)
goto free;
@@ -561,11 +540,11 @@ getaddrinfo(hostname, servname, hints, res)
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex))) {
+ WILD_SOCKTYPE(ex))) {
continue;
}
if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex))) {
+ WILD_PROTOCOL(ex))) {
continue;
}
@@ -574,7 +553,8 @@ getaddrinfo(hostname, servname, hints, res)
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
- error = explore_fqdn(pai, hostname, servname, &cur->ai_next);
+ error = explore_fqdn(pai, hostname, servname,
+ &cur->ai_next);
while (cur && cur->ai_next)
cur = cur->ai_next;
@@ -602,82 +582,6 @@ getaddrinfo(hostname, servname, hints, res)
return error;
}
-static char *
-_hgetword(char **pp)
-{
- char c, *p, *ret;
- const char *sp;
- static const char sep[] = "# \t\n";
-
- ret = NULL;
- for (p = *pp; (c = *p) != '\0'; p++) {
- for (sp = sep; *sp != '\0'; sp++) {
- if (c == *sp)
- break;
- }
- if (c == '#')
- p[1] = '\0'; /* ignore rest of line */
- if (ret == NULL) {
- if (*sp == '\0')
- ret = p;
- } else {
- if (*sp != '\0') {
- *p++ = '\0';
- break;
- }
- }
- }
- *pp = p;
- if (ret == NULL || *ret == '\0')
- return NULL;
- return ret;
-}
-
-/*
- * Initialize hostconf structure.
- */
-
-static void
-_hostconf_init(void)
-{
- FILE *fp;
- int n;
- char *p, *line;
- char buf[BUFSIZ];
-
- _hostconf_init_done = 1;
- n = 0;
- p = HOSTCONF;
- if ((fp = fopen(p, "r")) == NULL)
- return;
- while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
- line = buf;
- if ((p = _hgetword(&line)) == NULL)
- continue;
- do {
- if (strcmp(p, "hosts") == 0
- || strcmp(p, "local") == 0
- || strcmp(p, "file") == 0
- || strcmp(p, "files") == 0)
- _hostconf[n++].byname = _files_getaddrinfo;
- else if (strcmp(p, "dns") == 0
- || strcmp(p, "bind") == 0)
- _hostconf[n++].byname = _dns_getaddrinfo;
-#ifdef YP
- else if (strcmp(p, "nis") == 0)
- _hostconf[n++].byname = _nis_getaddrinfo;
-#endif
- } while ((p = _hgetword(&line)) != NULL);
- }
- fclose(fp);
- if (n < 0) {
- /* no keyword found. do not change default configuration */
- return;
- }
- for (; n < MAXHOSTCONF; n++)
- _hostconf[n].byname = NULL;
-}
-
/*
* FQDN hostname, DNS lookup
*/
@@ -690,10 +594,15 @@ explore_fqdn(pai, hostname, servname, res)
{
struct addrinfo *result;
struct addrinfo *cur;
- int error = 0, i;
+ int error = 0;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_getaddrinfo, NULL)
+ { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
+ NS_NIS_CB(_yp_getaddrinfo, NULL)
+ { 0 }
+ };
result = NULL;
- *res = NULL;
/*
* if the servname does not match socktype/protocol, ignore it.
@@ -701,23 +610,30 @@ explore_fqdn(pai, hostname, servname, res)
if (get_portmatch(pai, servname) != 0)
return 0;
- if (!_hostconf_init_done)
- _hostconf_init();
-
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (!_hostconf[i].byname)
- continue;
- error = (*_hostconf[i].byname)(pai, hostname, &result);
- if (error != 0)
- continue;
+ switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
+ default_dns_files, hostname, pai)) {
+ case NS_TRYAGAIN:
+ error = EAI_AGAIN;
+ goto free;
+ case NS_UNAVAIL:
+ error = EAI_FAIL;
+ goto free;
+ case NS_NOTFOUND:
+ error = EAI_NODATA;
+ goto free;
+ case NS_SUCCESS:
+ error = 0;
for (cur = result; cur; cur = cur->ai_next) {
GET_PORT(cur, servname);
/* canonname should be filled already */
}
- *res = result;
- return 0;
+ break;
}
+ *res = result;
+
+ return 0;
+
free:
if (result)
freeaddrinfo(result);
@@ -887,6 +803,7 @@ explore_numeric_scope(pai, hostname, servname, res)
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
+
if (!afd->a_scoped)
return explore_numeric(pai, hostname, servname, res);
@@ -1003,14 +920,13 @@ get_ai(pai, afd, addr)
ai->ai_addr->sa_len = afd->a_socklen;
ai->ai_addrlen = afd->a_socklen;
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
- p = (char *)(ai->ai_addr);
+ p = (char *)(void *)(ai->ai_addr);
#ifdef FAITH
if (translate == 1)
- memcpy(p + afd->a_off, &faith_prefix, afd->a_addrlen);
+ memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
else
#endif
- memcpy(p + afd->a_off, addr, afd->a_addrlen);
-
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
return ai;
}
@@ -1152,7 +1068,6 @@ addrconfig(pai)
else
_close(s);
}
-
}
if (af != AF_UNSPEC) {
if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
@@ -1212,6 +1127,7 @@ ip6_str2scopeid(scope, sin6)
static const char AskedForGot[] =
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
#endif
+static FILE *hostf = NULL;
static struct addrinfo *
getanswer(answer, anslen, qname, qtype, pai)
@@ -1415,17 +1331,21 @@ getanswer(answer, anslen, qname, qtype, pai)
/*ARGSUSED*/
static int
-_dns_getaddrinfo(pai, hostname, res)
- const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
+_dns_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
struct addrinfo *ai;
querybuf buf, buf2;
const char *name;
+ const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct res_target q, q2;
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
memset(&q, 0, sizeof(q2));
memset(&q2, 0, sizeof(q2));
memset(&sentinel, 0, sizeof(sentinel));
@@ -1457,10 +1377,10 @@ _dns_getaddrinfo(pai, hostname, res)
q.anslen = sizeof(buf);
break;
default:
- return EAI_FAIL;
+ return NS_UNAVAIL;
}
- if (res_searchN(hostname, &q) < 0)
- return EAI_NODATA;
+ if (res_searchN(name, &q) < 0)
+ return NS_NOTFOUND;
ai = getanswer(&buf, q.n, q.name, q.qtype, pai);
if (ai) {
cur->ai_next = ai;
@@ -1475,19 +1395,36 @@ _dns_getaddrinfo(pai, hostname, res)
if (sentinel.ai_next == NULL)
switch (h_errno) {
case HOST_NOT_FOUND:
- return EAI_NODATA;
+ return NS_NOTFOUND;
case TRY_AGAIN:
- return EAI_AGAIN;
+ return NS_TRYAGAIN;
default:
- return EAI_FAIL;
+ return NS_UNAVAIL;
}
- *res = sentinel.ai_next;
- return 0;
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
+}
+
+static void
+_sethtent()
+{
+ if (!hostf)
+ hostf = fopen(_PATH_HOSTS, "r" );
+ else
+ rewind(hostf);
+}
+
+static void
+_endhtent()
+{
+ if (hostf) {
+ (void) fclose(hostf);
+ hostf = NULL;
+ }
}
static struct addrinfo *
-_gethtent(hostf, name, pai)
- FILE *hostf;
+_gethtent(name, pai)
const char *name;
const struct addrinfo *pai;
{
@@ -1498,6 +1435,8 @@ _gethtent(hostf, name, pai)
const char *addr;
char hostbuf[8*1024];
+ if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
+ return (NULL);
again:
if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
return (NULL);
@@ -1557,102 +1496,181 @@ found:
/*ARGSUSED*/
static int
-_files_getaddrinfo(pai, hostname, res)
- const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
+_files_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- FILE *hostf;
+ const char *name;
+ const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct addrinfo *p;
- sentinel.ai_next = NULL;
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
- if ((hostf = fopen(_PATH_HOSTS, "r")) == NULL)
- return EAI_FAIL;
- while ((p = _gethtent(hostf, hostname, pai)) != NULL) {
+ _sethtent();
+ while ((p = _gethtent(name, pai)) != NULL) {
cur->ai_next = p;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- fclose(hostf);
+ _endhtent();
- if (!sentinel.ai_next)
- return EAI_NODATA;
-
- *res = sentinel.ai_next;
- return 0;
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ if (sentinel.ai_next == NULL)
+ return NS_NOTFOUND;
+ return NS_SUCCESS;
}
#ifdef YP
+static char *__ypdomain;
+
/*ARGSUSED*/
-static int
-_nis_getaddrinfo(pai, hostname, res)
+static struct addrinfo *
+_yphostent(line, pai)
+ char *line;
const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
{
- struct hostent *hp;
- int h_error;
- int af;
struct addrinfo sentinel, *cur;
- int i;
- const struct afd *afd;
+ struct addrinfo hints, *res, *res0;
int error;
+ char *p = line;
+ const char *addr, *canonname;
+ char *nextline;
+ char *cp;
- sentinel.ai_next = NULL;
+ addr = canonname = NULL;
+
+ memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
- af = (pai->ai_family == AF_UNSPEC) ? AF_INET : pai->ai_family;
- if (af != AF_INET)
- return (EAI_ADDRFAMILY);
+nextline:
+ /* terminate line */
+ cp = strchr(p, '\n');
+ if (cp) {
+ *cp++ = '\0';
+ nextline = cp;
+ } else
+ nextline = NULL;
- if ((hp = _gethostbynisname(hostname, af)) == NULL) {
- switch (errno) {
- /* XXX: should be filled in */
- default:
- error = EAI_FAIL;
- break;
- }
- } else if (hp->h_name == NULL ||
- hp->h_name[0] == 0 || hp->h_addr_list[0] == NULL) {
- hp = NULL;
- error = EAI_FAIL;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL) {
+ if (canonname == NULL)
+ return (NULL);
+ else
+ goto done;
}
+ *cp++ = '\0';
- if (hp == NULL)
- return error;
+ addr = p;
- for (i = 0; hp->h_addr_list[i] != NULL; i++) {
- if (hp->h_addrtype != af)
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
continue;
+ }
+ if (!canonname)
+ canonname = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
- afd = find_afd(hp->h_addrtype);
- if (afd == NULL)
- continue;
+ hints = *pai;
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(addr, NULL, &hints, &res0);
+ if (error == 0) {
+ for (res = res0; res; res = res->ai_next) {
+ /* cover it up */
+ res->ai_flags = pai->ai_flags;
- GET_AI(cur->ai_next, afd, hp->h_addr_list[i]);
- if ((pai->ai_flags & AI_CANONNAME) != 0) {
- /*
- * RFC2553 says that ai_canonname will be set only for
- * the first element. we do it for all the elements,
- * just for convenience.
- */
- GET_CANONNAME(cur->ai_next, hp->h_name);
+ if (pai->ai_flags & AI_CANONNAME)
+ (void)get_canonname(pai, res, canonname);
}
-
+ } else
+ res0 = NULL;
+ if (res0) {
+ cur->ai_next = res0;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- *res = sentinel.ai_next;
- return 0;
+ if (nextline) {
+ p = nextline;
+ goto nextline;
+ }
-free:
- if (sentinel.ai_next)
- freeaddrinfo(sentinel.ai_next);
- return error;
+done:
+ return sentinel.ai_next;
+}
+
+/*ARGSUSED*/
+static int
+_yp_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ struct addrinfo sentinel, *cur;
+ struct addrinfo *ai = NULL;
+ static char *__ypcurrent;
+ int __ypcurrentlen, r;
+ const char *name;
+ const struct addrinfo *pai;
+
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ if (!__ypdomain) {
+ if (_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+ if (__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+
+ /* hosts.byname is only for IPv4 (Solaris8) */
+ if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
+ r = yp_match(__ypdomain, "hosts.byname", name,
+ (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+ if (r == 0) {
+ struct addrinfo ai4;
+
+ ai4 = *pai;
+ ai4.ai_family = AF_INET;
+ ai = _yphostent(__ypcurrent, &ai4);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+ }
+
+ /* ipnodes.byname can hold both IPv4/v6 */
+ r = yp_match(__ypdomain, "ipnodes.byname", name,
+ (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+ if (r == 0) {
+ ai = _yphostent(__ypcurrent, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+
+ if (sentinel.ai_next == NULL) {
+ h_errno = HOST_NOT_FOUND;
+ return NS_NOTFOUND;
+ }
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
}
#endif
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c
index a5a3e7b..4a56655 100644
--- a/lib/libc/net/gethostbydns.c
+++ b/lib/libc/net/gethostbydns.c
@@ -74,6 +74,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include "res_config.h"
@@ -474,19 +476,23 @@ __dns_getanswer(answer, anslen, qname, qtype)
return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
}
-struct hostent *
-_gethostbydnsname(name, af)
+int
+_dns_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
const char *name;
int af;
-{
querybuf buf;
register const char *cp;
char *bp;
int n, size, type, len;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ *(struct hostent **)rval = NULL;
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
switch (af) {
@@ -501,7 +507,7 @@ _gethostbydnsname(name, af)
default:
h_errno = NETDB_INTERNAL;
errno = EAFNOSUPPORT;
- return (NULL);
+ return NS_UNAVAIL;
}
host.h_addrtype = af;
@@ -531,7 +537,7 @@ _gethostbydnsname(name, af)
*/
if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
strncpy(hostbuf, name, MAXDNAME);
hostbuf[MAXDNAME] = '\0';
@@ -546,7 +552,8 @@ _gethostbydnsname(name, af)
if (_res.options & RES_USE_INET6)
_map_v4v6_hostent(&host, &bp, &len);
h_errno = NETDB_SUCCESS;
- return (&host);
+ *(struct hostent **)rval = &host;
+ return NS_SUCCESS;
}
if (!isdigit((unsigned char)*cp) && *cp != '.')
break;
@@ -564,7 +571,7 @@ _gethostbydnsname(name, af)
*/
if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
strncpy(hostbuf, name, MAXDNAME);
hostbuf[MAXDNAME] = '\0';
@@ -577,7 +584,8 @@ _gethostbydnsname(name, af)
h_addr_ptrs[1] = NULL;
host.h_addr_list = h_addr_ptrs;
h_errno = NETDB_SUCCESS;
- return (&host);
+ *(struct hostent **)rval = &host;
+ return NS_SUCCESS;
}
if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
break;
@@ -585,17 +593,18 @@ _gethostbydnsname(name, af)
if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
dprintf("res_search failed (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
- return (gethostanswer(&buf, n, name, type));
+ *(struct hostent **)rval = gethostanswer(&buf, n, name, type);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct hostent *
-_gethostbydnsaddr(addr, len, af)
+int
+_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
const char *addr; /* XXX should have been def'd as u_char! */
int len, af;
-{
- const u_char *uaddr = (const u_char *)addr;
+ const u_char *uaddr;
static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
int n, size;
@@ -608,10 +617,17 @@ _gethostbydnsaddr(addr, len, af)
u_long old_options;
char hname2[MAXDNAME+1];
#endif /*SUNSECURITY*/
+
+ addr = va_arg(ap, const char *);
+ uaddr = (const u_char *)addr;
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval = NULL;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
if (af == AF_INET6 && len == IN6ADDRSZ &&
(!bcmp(uaddr, mapped, sizeof mapped) ||
@@ -632,12 +648,12 @@ _gethostbydnsaddr(addr, len, af)
default:
errno = EAFNOSUPPORT;
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
if (size != len) {
errno = EINVAL;
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
switch (af) {
case AF_INET:
@@ -662,14 +678,14 @@ _gethostbydnsaddr(addr, len, af)
n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
if (n < 0) {
dprintf("res_query failed (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
if (n > sizeof buf.buf) {
dprintf("static buffer is too small (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR)))
- return (NULL); /* h_errno was set by gethostanswer() */
+ return NS_NOTFOUND; /* h_errno was set by gethostanswer() */
#ifdef SUNSECURITY
if (af == AF_INET) {
/*
@@ -687,7 +703,7 @@ _gethostbydnsaddr(addr, len, af)
hname2, inet_ntoa(*((struct in_addr *)addr)));
_res.options = old_options;
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
_res.options = old_options;
for (haddr = rhp->h_addr_list; *haddr; haddr++)
@@ -698,7 +714,7 @@ _gethostbydnsaddr(addr, len, af)
"gethostbyaddr: A record of %s != PTR record [%s]",
hname2, inet_ntoa(*((struct in_addr *)addr)));
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
}
#endif /*SUNSECURITY*/
@@ -713,7 +729,8 @@ _gethostbydnsaddr(addr, len, af)
hp->h_length = IN6ADDRSZ;
}
h_errno = NETDB_SUCCESS;
- return (hp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#ifdef RESOLVSORT
diff --git a/lib/libc/net/gethostbyht.c b/lib/libc/net/gethostbyht.c
index cd5f0f4..eeecd22 100644
--- a/lib/libc/net/gethostbyht.c
+++ b/lib/libc/net/gethostbyht.c
@@ -65,6 +65,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX */
#include <resolv.h> /* XXX */
@@ -163,13 +165,16 @@ gethostent()
return (&host);
}
-struct hostent *
-_gethostbyhtname(name, af)
+int
+_ht_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
const char *name;
int af;
-{
register struct hostent *p;
register char **cp;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
sethostent(0);
while ((p = gethostent()) != NULL) {
@@ -183,20 +188,28 @@ _gethostbyhtname(name, af)
}
found:
endhostent();
- return (p);
+ *(struct hostent **)rval = p;
+
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct hostent *
-_gethostbyhtaddr(addr, len, af)
+int
+_ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
const char *addr;
int len, af;
-{
register struct hostent *p;
+ addr = va_arg(ap, const char *);
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
sethostent(0);
while ((p = gethostent()) != NULL)
if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
break;
endhostent();
- return (p);
+
+ *(struct hostent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
diff --git a/lib/libc/net/gethostbyname.3 b/lib/libc/net/gethostbyname.3
index e513d74..0e2006e 100644
--- a/lib/libc/net/gethostbyname.3
+++ b/lib/libc/net/gethostbyname.3
@@ -78,10 +78,15 @@ following structure describing an internet host
referenced by name or by address, respectively.
This structure contains either the information obtained from the name server,
.Xr named 8 ,
-or broken-out fields from a line in
-.Pa /etc/hosts .
-If the local name server is not running these routines do a lookup in
-.Pa /etc/hosts .
+broken-out fields from a line in
+.Pa /etc/hosts ,
+or database entries supplied by the
+.Xr yp 4
+system.
+The order of the lookups is controlled by the
+.Sq hosts
+entry in
+.Xr nsswitch.conf 5 .
.Bd -literal
struct hostent {
char *h_name; /* official name of host */
@@ -188,9 +193,9 @@ value of the
.Fa err
parameter.
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c
index 82e0b3d..518d512 100644
--- a/lib/libc/net/gethostbynis.c
+++ b/lib/libc/net/gethostbynis.c
@@ -39,6 +39,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
@@ -52,7 +54,6 @@ static char rcsid[] = "$FreeBSD$";
static char *host_aliases[MAXALIASES];
static char hostaddr[MAXADDRS];
static char *host_addrs[2];
-#endif /* YP */
static struct hostent *
_gethostbynis(name, map, af)
@@ -60,7 +61,6 @@ _gethostbynis(name, map, af)
char *map;
int af;
{
-#ifdef YP
register char *cp, **q;
char *result;
int resultlen,size;
@@ -122,24 +122,64 @@ _gethostbynis(name, map, af)
}
*q = NULL;
return (&h);
-#else
- return (NULL);
-#endif /* YP */
}
+#endif /* YP */
+/* XXX _gethostbynisname/_gethostbynisaddr only used by getaddrinfo */
struct hostent *
-_gethostbynisname(name, af)
- const char *name;
- int af;
+_gethostbynisname(const char *name, int af)
{
+#ifdef YP
return _gethostbynis(name, "hosts.byname", af);
+#else
+ return NULL;
+#endif
}
struct hostent *
-_gethostbynisaddr(addr, len, af)
+_gethostbynisaddr(const char *addr, int len, int af)
+{
+#ifdef YP
+ return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),
+ "hosts.byaddr", af);
+#else
+ return NULL;
+#endif
+}
+
+
+int
+_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ const char *name;
+ int af;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval = _gethostbynis(name, "hosts.byname", af);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
+}
+
+int
+_nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
const char *addr;
int len;
int af;
-{
- return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af);
+
+ addr = va_arg(ap, const char *);
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval =_gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 010e4db..fcfc979 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -37,87 +37,25 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX hack for _res */
#include <resolv.h> /* XXX hack for _res */
-#define _PATH_HOSTCONF "/etc/host.conf"
-
-enum service_type {
- SERVICE_NONE = 0,
- SERVICE_BIND,
- SERVICE_HOSTS,
- SERVICE_NIS };
-#define SERVICE_MAX SERVICE_NIS
-
-static struct {
- const char *name;
- enum service_type type;
-} service_names[] = {
- { "hosts", SERVICE_HOSTS },
- { "/etc/hosts", SERVICE_HOSTS },
- { "hosttable", SERVICE_HOSTS },
- { "htable", SERVICE_HOSTS },
- { "bind", SERVICE_BIND },
- { "dns", SERVICE_BIND },
- { "domain", SERVICE_BIND },
- { "yp", SERVICE_NIS },
- { "yellowpages", SERVICE_NIS },
- { "nis", SERVICE_NIS },
- { 0, SERVICE_NONE }
+extern int _ht_gethostbyname(void *, void *, va_list);
+extern int _dns_gethostbyname(void *, void *, va_list);
+extern int _nis_gethostbyname(void *, void *, va_list);
+extern int _ht_gethostbyaddr(void *, void *, va_list);
+extern int _dns_gethostbyaddr(void *, void *, va_list);
+extern int _nis_gethostbyaddr(void *, void *, va_list);
+
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
};
-static enum service_type service_order[SERVICE_MAX + 1];
-static int service_done = 0;
-
-static enum service_type
-get_service_name(const char *name) {
- int i;
- for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
- if(!strcasecmp(name, service_names[i].name)) {
- return service_names[i].type;
- }
- }
- return SERVICE_NONE;
-}
-
-static void
-init_services()
-{
- char *cp, *p, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
-
- if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
- /* make some assumptions */
- service_order[0] = SERVICE_BIND;
- service_order[1] = SERVICE_HOSTS;
- service_order[2] = SERVICE_NONE;
- } else {
- while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
- if(buf[0] == '#')
- continue;
-
- p = buf;
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- if (cp == NULL)
- continue;
- do {
- if (isalpha((unsigned char)cp[0])) {
- service_order[cc] = get_service_name(cp);
- if(service_order[cc] != SERVICE_NONE)
- cc++;
- }
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- } while(cp != NULL && cc < SERVICE_MAX);
- }
- service_order[cc] = SERVICE_NONE;
- fclose(fd);
- }
- service_done = 1;
-}
-
struct hostent *
gethostbyname(const char *name)
{
@@ -135,56 +73,44 @@ struct hostent *
gethostbyname2(const char *name, int type)
{
struct hostent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return NULL;
- case SERVICE_HOSTS:
- hp = _gethostbyhtname(name, type);
- break;
- case SERVICE_BIND:
- hp = _gethostbydnsname(name, type);
- break;
- case SERVICE_NIS:
- hp = _gethostbynisname(name, type);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyname, NULL)
+ { NSSRC_DNS, _dns_gethostbyname, NULL },
+ NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname",
+ default_src, name, type);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
struct hostent *
gethostbyaddr(const char *addr, int len, int type)
{
struct hostent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return 0;
- case SERVICE_HOSTS:
- hp = _gethostbyhtaddr(addr, len, type);
- break;
- case SERVICE_BIND:
- hp = _gethostbydnsaddr(addr, len, type);
- break;
- case SERVICE_NIS:
- hp = _gethostbynisaddr(addr, len, type);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyaddr, NULL)
+ { NSSRC_DNS, _dns_gethostbyaddr, NULL },
+ NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
+ default_src, addr, len, type);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
#ifdef _THREAD_SAFE
diff --git a/lib/libc/net/getipnodebyname.3 b/lib/libc/net/getipnodebyname.3
index 618f5a3..5eec582 100644
--- a/lib/libc/net/getipnodebyname.3
+++ b/lib/libc/net/getipnodebyname.3
@@ -405,9 +405,9 @@ or
.Fn getipnodebyaddr .
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
@@ -429,6 +429,7 @@ The meanings of each error code are described in
.Xr gethostbyname 3 ,
.Xr gethostbyaddr 3 ,
.Xr hosts 5 ,
+.Xr nsswitch.conf 5 ,
.Xr services 5 ,
.Xr hostname 7 ,
.Xr named 8
diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3
index 113563f..0289b9f 100644
--- a/lib/libc/net/getnameinfo.3
+++ b/lib/libc/net/getnameinfo.3
@@ -226,9 +226,9 @@ printf("host=%s\\n", hbuf);
.Ed
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
diff --git a/lib/libc/net/getnetbydns.c b/lib/libc/net/getnetbydns.c
index 65d9d2d..5827103 100644
--- a/lib/libc/net/getnetbydns.c
+++ b/lib/libc/net/getnetbydns.c
@@ -77,6 +77,8 @@ static char rcsid[] = "$FreeBSD$";
#include <string.h>
#include <unistd.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include "res_config.h"
@@ -218,11 +220,11 @@ static char *net_aliases[MAXALIASES], netbuf[PACKETSZ];
return (NULL);
}
-struct netent *
-_getnetbydnsaddr(net, net_type)
- register unsigned long net;
- register int net_type;
+int
+_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
+ unsigned long net;
+ int net_type;
unsigned int netbr[4];
int nn, anslen;
querybuf buf;
@@ -230,8 +232,13 @@ _getnetbydnsaddr(net, net_type)
unsigned long net2;
struct netent *net_entry;
+ net = va_arg(ap, unsigned long);
+ net_type = va_arg(ap, int);
+
+ *(struct netent **)rval = NULL;
+
if (net_type != AF_INET)
- return (NULL);
+ return NS_UNAVAIL;
for (nn = 4, net2 = net; net2; net2 >>= 8)
netbr[--nn] = net2 & 0xff;
@@ -257,7 +264,7 @@ _getnetbydnsaddr(net, net_type)
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- return (NULL);
+ return NS_UNAVAIL;
}
net_entry = getnetanswer(&buf, anslen, BYADDR);
if (net_entry) {
@@ -267,22 +274,27 @@ _getnetbydnsaddr(net, net_type)
while ((u_net & 0xff) == 0 && u_net != 0)
u_net >>= 8;
net_entry->n_net = u_net;
- return (net_entry);
+ *(struct netent **)rval = net_entry;
+ return NS_SUCCESS;
}
- return (NULL);
+ return NS_NOTFOUND;
}
-struct netent *
-_getnetbydnsname(net)
- register const char *net;
+int
+_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *net;
int anslen;
querybuf buf;
char qbuf[MAXDNAME];
+ net = va_arg(ap, const char *);
+
+ *(struct netent**)rval = NULL;
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
strncpy(qbuf, net, sizeof(qbuf) - 1);
qbuf[sizeof(qbuf) - 1] = '\0';
@@ -292,9 +304,10 @@ _getnetbydnsname(net)
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- return (NULL);
+ return NS_UNAVAIL;
}
- return getnetanswer(&buf, anslen, BYNAME);
+ *(struct netent**)rval = getnetanswer(&buf, anslen, BYNAME);
+ return (*(struct netent**)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
void
diff --git a/lib/libc/net/getnetbyht.c b/lib/libc/net/getnetbyht.c
index ab164b1..b5f73be 100644
--- a/lib/libc/net/getnetbyht.c
+++ b/lib/libc/net/getnetbyht.c
@@ -55,6 +55,8 @@ static chat rcsid[] = "$FreeBSD$";
#include <netdb.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#define MAXALIASES 35
@@ -135,13 +137,15 @@ again:
return (&net);
}
-struct netent *
-_getnetbyhtname(name)
- register const char *name;
+int
+_ht_getnetbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
register struct netent *p;
register char **cp;
+ name = va_arg(ap, const char *);
+
setnetent(_net_stayopen);
while ( (p = getnetent()) ) {
if (strcasecmp(p->n_name, name) == 0)
@@ -153,21 +157,26 @@ _getnetbyhtname(name)
found:
if (!_net_stayopen)
endnetent();
- return (p);
+ *(struct netent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct netent *
-_getnetbyhtaddr(net, type)
- register unsigned long net;
- register int type;
+int
+_ht_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
+ unsigned long net;
+ int type;
register struct netent *p;
+ net = va_arg(ap, unsigned long);
+ type = va_arg(ap, int);
+
setnetent(_net_stayopen);
while ( (p = getnetent()) )
if (p->n_addrtype == type && p->n_net == net)
break;
if (!_net_stayopen)
endnetent();
- return (p);
+ *(struct netent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
diff --git a/lib/libc/net/getnetbynis.c b/lib/libc/net/getnetbynis.c
index 0ab7073..d226b01 100644
--- a/lib/libc/net/getnetbynis.c
+++ b/lib/libc/net/getnetbynis.c
@@ -38,6 +38,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h>
#ifdef YP
#include <rpc/rpc.h>
@@ -50,15 +52,10 @@ static char rcsid[] = "$FreeBSD$";
#ifdef YP
static char *host_aliases[MAXALIASES];
-#endif /* YP */
static struct netent *
-_getnetbynis(name, map, af)
- const char *name;
- char *map;
- int af;
+_getnetbynis(const char *name, char *map, int af)
{
-#ifdef YP
register char *cp, **q;
static char *result;
int resultlen;
@@ -117,32 +114,45 @@ _getnetbynis(name, map, af)
}
*q = NULL;
return (&h);
-#else
- return (NULL);
-#endif
}
+#endif /* YP */
-struct netent *
-_getnetbynisname(name)
- const char *name;
+int
+_nis_getnetbyname(void *rval, void *cb_data, va_list ap)
{
- return _getnetbynis(name, "networks.byname", AF_INET);
+#ifdef YP
+ const char *name;
+
+ name = va_arg(ap, const char *);
+
+ *(struct netent **)rval = _getnetbynis(name, "networks.byname", AF_INET);
+ return (*(struct netent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
+
}
-struct netent *
-_getnetbynisaddr(addr, af)
+int
+_nis_getnetbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
unsigned long addr;
int af;
-{
char *str, *cp;
unsigned long net2;
int nn;
unsigned int netbr[4];
char buf[MAXDNAME];
+ addr = va_arg(ap, unsigned long);
+ af = va_arg(ap, int);
+
+ *(struct netent **)rval = NULL;
+
if (af != AF_INET) {
errno = EAFNOSUPPORT;
- return (NULL);
+ return NS_UNAVAIL;
}
for (nn = 4, net2 = addr; net2; net2 >>= 8) {
@@ -173,5 +183,9 @@ _getnetbynisaddr(addr, af)
cp = str + (strlen(str) - 2);
}
- return _getnetbynis(str, "networks.byaddr", af);
+ *(struct netent **)rval = _getnetbynis(str, "networks.byaddr", af);
+ return (*(struct netent**)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif /* YP */
}
diff --git a/lib/libc/net/getnetent.3 b/lib/libc/net/getnetent.3
index 086f4c3..de3e9df 100644
--- a/lib/libc/net/getnetent.3
+++ b/lib/libc/net/getnetent.3
@@ -64,10 +64,18 @@ and
.Fn getnetbyaddr
functions
each return a pointer to an object with the
-following structure
-containing the broken-out
-fields of a line in the network data base,
-.Pa /etc/networks .
+following structure describing an internet network.
+This structure contains either the information obtained
+from the nameserver,
+.Xr named 8 ,
+broken-out fields of a line in the network data base
+.Pa /etc/networks ,
+or entries supplied by the
+.Xr yp 4
+system. The order of the lookups is controlled by the
+`networks' entry in
+.Xr nsswitch.conf 5 .
+.Pp
.Bd -literal -offset indent
struct netent {
char *n_name; /* official name of net */
@@ -129,8 +137,10 @@ must be
.Dv AF_INET .
Network numbers are supplied in host order.
.Sh FILES
-.Bl -tag -width /etc/networks -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/networks
+.It Pa /etc/nsswitch.conf
+.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
Null pointer
diff --git a/lib/libc/net/getnetnamadr.c b/lib/libc/net/getnetnamadr.c
index cb5871b..6d9dbfa 100644
--- a/lib/libc/net/getnetnamadr.c
+++ b/lib/libc/net/getnetnamadr.c
@@ -36,142 +36,66 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
-
-#ifndef _PATH_NETCONF
-#define _PATH_NETCONF "/etc/host.conf"
-#endif
-
-enum service_type {
- SERVICE_NONE = 0,
- SERVICE_BIND,
- SERVICE_TABLE,
- SERVICE_NIS };
-#define SERVICE_MAX SERVICE_NIS
-
-static struct {
- const char *name;
- enum service_type type;
-} service_names[] = {
- { "hosts", SERVICE_TABLE },
- { "/etc/hosts", SERVICE_TABLE },
- { "hosttable", SERVICE_TABLE },
- { "htable", SERVICE_TABLE },
- { "bind", SERVICE_BIND },
- { "dns", SERVICE_BIND },
- { "domain", SERVICE_BIND },
- { "yp", SERVICE_NIS },
- { "yellowpages", SERVICE_NIS },
- { "nis", SERVICE_NIS },
- { 0, SERVICE_NONE }
+#include <stdarg.h>
+#include <nsswitch.h>
+
+extern int _ht_getnetbyname(void *, void *, va_list);
+extern int _dns_getnetbyname(void *, void *, va_list);
+extern int _nis_getnetbyname(void *, void *, va_list);
+extern int _ht_getnetbyaddr(void *, void *, va_list);
+extern int _dns_getnetbyaddr(void *, void *, va_list);
+extern int _nis_getnetbyaddr(void *, void *, va_list);
+
+/* Network lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
};
-static enum service_type service_order[SERVICE_MAX + 1];
-static int service_done = 0;
-
-static enum service_type
-get_service_name(const char *name) {
- int i;
- for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
- if(!strcasecmp(name, service_names[i].name)) {
- return service_names[i].type;
- }
- }
- return SERVICE_NONE;
-}
-
-static void
-init_services()
-{
- char *cp, *p, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
-
- if ((fd = (FILE *)fopen(_PATH_NETCONF, "r")) == NULL) {
- /* make some assumptions */
- service_order[0] = SERVICE_TABLE;
- service_order[1] = SERVICE_NONE;
- } else {
- while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
- if(buf[0] == '#')
- continue;
-
- p = buf;
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- if (cp == NULL)
- continue;
- do {
- if (isalpha((unsigned char)cp[0])) {
- service_order[cc] = get_service_name(cp);
- if(service_order[cc] != SERVICE_NONE)
- cc++;
- }
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- } while(cp != NULL && cc < SERVICE_MAX);
- }
- service_order[cc] = SERVICE_NONE;
- fclose(fd);
- }
- service_done = 1;
-}
-
struct netent *
getnetbyname(const char *name)
{
struct netent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return NULL;
- case SERVICE_TABLE:
- hp = _getnetbyhtname(name);
- break;
- case SERVICE_BIND:
- hp = _getnetbydnsname(name);
- break;
- case SERVICE_NIS:
- hp = _getnetbynisname(name);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyname, NULL)
+ { NSSRC_DNS, _dns_getnetbyname, NULL },
+ NS_NIS_CB(_nis_getnetbyname, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_NETWORKS, "getnetbyname",
+ default_src, name);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
struct netent *
-getnetbyaddr(addr, af)
- u_long addr;
- int af;
+getnetbyaddr(u_long addr, int af)
{
struct netent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return 0;
- case SERVICE_TABLE:
- hp = _getnetbyhtaddr(addr, af);
- break;
- case SERVICE_BIND:
- hp = _getnetbydnsaddr(addr, af);
- break;
- case SERVICE_NIS:
- hp = _getnetbynisaddr(addr, af);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyaddr, NULL)
+ { NSSRC_DNS, _dns_getnetbyaddr, NULL },
+ NS_NIS_CB(_nis_getnetbyaddr, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "getnetbyaddr",
+ default_src, addr, af);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
void
diff --git a/lib/libc/net/hesiod.3 b/lib/libc/net/hesiod.3
new file mode 100644
index 0000000..49e7d67
--- /dev/null
+++ b/lib/libc/net/hesiod.3
@@ -0,0 +1,136 @@
+.\" $NetBSD: hesiod.3,v 1.1 1999/01/25 03:43:04 lukem Exp $
+.\" $FreeBSD$
+.\"
+.\" from: #Id: hesiod.3,v 1.9.2.1 1997/01/03 21:02:23 ghudson Exp #
+.\"
+.\" Copyright 1988, 1996 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.TH HESIOD 3 "30 November 1996"
+.SH NAME
+hesiod, hesiod_init, hesiod_resolve, hesiod_free_list, hesiod_to_bind, hesiod_end \- Hesiod name server interface library
+.SH SYNOPSIS
+.nf
+.B #include <hesiod.h>
+.PP
+.B int hesiod_init(void **\fIcontext\fP)
+.B char **hesiod_resolve(void *\fIcontext\fP, const char *\fIname\fP,
+.B const char *\fItype\fP)
+.B void hesiod_free_list(void *\fIcontext\fP, char **\fIlist\fP);
+.B char *hesiod_to_bind(void *\fIcontext\fP, const char *\fIname\fP,
+.B const char *\fItype\fP)
+.B void hesiod_end(void *\fIcontext\fP)
+.PP
+.B cc file.c -lhesiod
+.fi
+.SH DESCRIPTION
+This family of functions allows you to perform lookups of Hesiod
+information, which is stored as text records in the Domain Name
+Service. To perform lookups, you must first initialize a
+.IR context ,
+an opaque object which stores information used internally by the
+library between calls.
+.I hesiod_init
+initializes a context, storing a pointer to the context in the
+location pointed to by the
+.I context
+argument.
+.I hesiod_end
+frees the resources used by a context.
+.PP
+.I hesiod_resolve
+is the primary interface to the library. If successful, it returns a
+list of one or more strings giving the records matching
+.I name
+and
+.IR type .
+The last element of the list is followed by a NULL pointer. It is the
+caller's responsibility to call
+.I hesiod_free_list
+to free the resources used by the returned list.
+.PP
+.I hesiod_to_bind
+converts
+.I name
+and
+.I type
+into the DNS name used by
+.IR hesiod_resolve .
+It is the caller's responsibility to free the returned string using
+.IR free .
+.SH RETURN VALUES
+If successful,
+.I hesiod_init
+returns 0; otherwise it returns \-1 and sets
+.I errno
+to indicate the error. On failure,
+.I hesiod_resolve
+and
+.I hesiod_to_bind
+return NULL and set the global variable
+.I errno
+to indicate the error.
+.SH ENVIRONMENT
+If the environment variable
+.B HES_DOMAIN
+is set, it will override the domain in the Hesiod configuration file.
+If the environment variable
+.B HESIOD_CONFIG
+is set, it specifies the location of the Hesiod configuration file.
+.SH SEE ALSO
+`Hesiod - Project Athena Technical Plan -- Name Service', named(8),
+hesiod.conf(5)
+.SH ERRORS
+Hesiod calls may fail because of:
+.IP ENOMEM
+Insufficient memory was available to carry out the requested
+operation.
+.IP ENOEXEC
+.I hesiod_init
+failed because the Hesiod configuration file was invalid.
+.IP ECONNREFUSED
+.I hesiod_resolve
+failed because no name server could be contacted to answer the query.
+.IP EMSGSIZE
+.I hesiod_resolve
+or
+.I hesiod_to_bind
+failed because the query or response was too big to fit into the
+packet buffers.
+.IP ENOENT
+.I hesiod_resolve
+failed because the name server had no text records matching
+.I name
+and
+.IR type ,
+or
+.I hesiod_to_bind
+failed because the
+.I name
+argument had a domain extension which could not be resolved with type
+``rhs-extension'' in the local Hesiod domain.
+.SH AUTHOR
+Steve Dyer, IBM/Project Athena
+.br
+Greg Hudson, MIT Team Athena
+.br
+Copyright 1987, 1988, 1995, 1996 by the Massachusetts Institute of Technology.
+.SH BUGS
+The strings corresponding to the
+.I errno
+values set by the Hesiod functions are not particularly indicative of
+what went wrong, especially for
+.I ENOEXEC
+and
+.IR ENOENT .
diff --git a/lib/libc/net/hesiod.c b/lib/libc/net/hesiod.c
new file mode 100644
index 0000000..f36757b
--- /dev/null
+++ b/lib/libc/net/hesiod.c
@@ -0,0 +1,572 @@
+/* $NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $ */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Copyright 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of the hesiod library. It implements the core
+ * portion of the hesiod resolver.
+ *
+ * This file is loosely based on an interim version of hesiod.c from
+ * the BIND IRS library, which was in turn based on an earlier version
+ * of this file. Extensive changes have been made on each step of the
+ * path.
+ *
+ * This implementation is not truly thread-safe at the moment because
+ * it uses res_send() and accesses _res.
+ */
+
+#include <sys/cdefs.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $";
+static char *rcsid = "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct hesiod_p {
+ char *lhs; /* normally ".ns" */
+ char *rhs; /* AKA the default hesiod domain */
+ int classes[2]; /* The class search order. */
+};
+
+#define MAX_HESRESP 1024
+
+static int read_config_file __P((struct hesiod_p *, const char *));
+static char **get_txt_records __P((int, const char *));
+static int init_context __P((void));
+static void translate_errors __P((void));
+
+
+/*
+ * hesiod_init --
+ * initialize a hesiod_p.
+ */
+int
+hesiod_init(context)
+ void **context;
+{
+ struct hesiod_p *ctx;
+ const char *p, *configname;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx) {
+ *context = ctx;
+ configname = getenv("HESIOD_CONFIG");
+ if (!configname)
+ configname = _PATH_HESIOD_CONF;
+ if (read_config_file(ctx, configname) >= 0) {
+ /*
+ * The default rhs can be overridden by an
+ * environment variable.
+ */
+ p = getenv("HES_DOMAIN");
+ if (p) {
+ if (ctx->rhs)
+ free(ctx->rhs);
+ ctx->rhs = malloc(strlen(p) + 2);
+ if (ctx->rhs) {
+ *ctx->rhs = '.';
+ strcpy(ctx->rhs + 1,
+ (*p == '.') ? p + 1 : p);
+ return 0;
+ } else
+ errno = ENOMEM;
+ } else
+ return 0;
+ }
+ } else
+ errno = ENOMEM;
+
+ if (ctx->lhs)
+ free(ctx->lhs);
+ if (ctx->rhs)
+ free(ctx->rhs);
+ if (ctx)
+ free(ctx);
+ return -1;
+}
+
+/*
+ * hesiod_end --
+ * Deallocates the hesiod_p.
+ */
+void
+hesiod_end(context)
+ void *context;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+
+ free(ctx->rhs);
+ if (ctx->lhs)
+ free(ctx->lhs);
+ free(ctx);
+}
+
+/*
+ * hesiod_to_bind --
+ * takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type)
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
+ const char *rhs;
+ int len;
+
+ strcpy(bindname, name);
+
+ /*
+ * Find the right right hand side to use, possibly
+ * truncating bindname.
+ */
+ p = strchr(bindname, '@');
+ if (p) {
+ *p++ = 0;
+ if (strchr(p, '.'))
+ rhs = name + (p - bindname);
+ else {
+ rhs_list = hesiod_resolve(context, p, "rhs-extension");
+ if (rhs_list)
+ rhs = *rhs_list;
+ else {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ } else
+ rhs = ctx->rhs;
+
+ /* See if we have enough room. */
+ len = strlen(bindname) + 1 + strlen(type);
+ if (ctx->lhs)
+ len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
+ len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
+ if (len > sizeof(bindname) - 1) {
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ /* Put together the rest of the domain. */
+ strcat(bindname, ".");
+ strcat(bindname, type);
+ /* Only append lhs if it isn't empty. */
+ if (ctx->lhs && ctx->lhs[0] != '\0' ) {
+ if (ctx->lhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, ctx->lhs);
+ }
+ if (rhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, rhs);
+
+ /* rhs_list is no longer needed, since we're done with rhs. */
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ /* Make a copy of the result and return it to the caller. */
+ ret = strdup(bindname);
+ if (!ret)
+ errno = ENOMEM;
+ return ret;
+}
+
+/*
+ * hesiod_resolve --
+ * Given a hesiod name and type, return an array of strings returned
+ * by the resolver.
+ */
+char **
+hesiod_resolve(context, name, type)
+ void *context;
+ const char *name;
+ const char *type;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname, **retvec;
+
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ return NULL;
+
+ retvec = get_txt_records(ctx->classes[0], bindname);
+ if (retvec == NULL && errno == ENOENT && ctx->classes[1])
+ retvec = get_txt_records(ctx->classes[1], bindname);
+
+ free(bindname);
+ return retvec;
+}
+
+/*ARGSUSED*/
+void
+hesiod_free_list(context, list)
+ void *context;
+ char **list;
+{
+ char **p;
+
+ if (list == NULL)
+ return;
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+
+/* read_config_file --
+ * Parse the /etc/hesiod.conf file. Returns 0 on success,
+ * -1 on failure. On failure, it might leave values in ctx->lhs
+ * or ctx->rhs which need to be freed by the caller.
+ */
+static int
+read_config_file(ctx, filename)
+ struct hesiod_p *ctx;
+ const char *filename;
+{
+ char *key, *data, *p, **which;
+ char buf[MAXDNAME + 7];
+ int n;
+ FILE *fp;
+
+ /* Set default query classes. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+
+ /* Try to open the configuration file. */
+ fp = fopen(filename, "r");
+ if (!fp) {
+ /* Use compiled in default domain names. */
+ ctx->lhs = strdup(DEF_LHS);
+ ctx->rhs = strdup(DEF_RHS);
+ if (ctx->lhs && ctx->rhs)
+ return 0;
+ else {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ ctx->lhs = NULL;
+ ctx->rhs = NULL;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ p = buf;
+ if (*p == '#' || *p == '\n' || *p == '\r')
+ continue;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ key = p;
+ while (*p != ' ' && *p != '\t' && *p != '=')
+ p++;
+ *p++ = 0;
+
+ while (isspace(*p) || *p == '=')
+ p++;
+ data = p;
+ while (!isspace(*p))
+ p++;
+ *p = 0;
+
+ if (strcasecmp(key, "lhs") == 0 ||
+ strcasecmp(key, "rhs") == 0) {
+ which = (strcasecmp(key, "lhs") == 0)
+ ? &ctx->lhs : &ctx->rhs;
+ *which = strdup(data);
+ if (!*which) {
+ errno = ENOMEM;
+ return -1;
+ }
+ } else {
+ if (strcasecmp(key, "classes") == 0) {
+ n = 0;
+ while (*data && n < 2) {
+ p = data;
+ while (*p && *p != ',')
+ p++;
+ if (*p)
+ *p++ = 0;
+ if (strcasecmp(data, "IN") == 0)
+ ctx->classes[n++] = C_IN;
+ else
+ if (strcasecmp(data, "HS") == 0)
+ ctx->classes[n++] =
+ C_HS;
+ data = p;
+ }
+ while (n < 2)
+ ctx->classes[n++] = 0;
+ }
+ }
+ }
+ fclose(fp);
+
+ if (!ctx->rhs || ctx->classes[0] == 0 ||
+ ctx->classes[0] == ctx->classes[1]) {
+ errno = ENOEXEC;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * get_txt_records --
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(qclass, name)
+ int qclass;
+ const char *name;
+{
+ HEADER *hp;
+ unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
+ char *dst, **list;
+ int ancount, qdcount, i, j, n, skip, type, class, len;
+
+ /* Make sure the resolver is initialized. */
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return NULL;
+
+ /* Construct the query. */
+ n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
+ NULL, qbuf, PACKETSZ);
+ if (n < 0)
+ return NULL;
+
+ /* Send the query. */
+ n = res_send(qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = ECONNREFUSED;
+ return NULL;
+ }
+ /* Parse the header of the result. */
+ hp = (HEADER *) (void *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ p = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /*
+ * Skip questions, trying to get to the answer section
+ * which follows.
+ */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + QFIXEDSZ > eom) {
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ p += skip + QFIXEDSZ;
+ }
+
+ /* Allocate space for the text record answers. */
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ /* Parse the answers. */
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ /* Parse the header of this answer. */
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + 10 > eom)
+ break;
+ type = p[skip + 0] << 8 | p[skip + 1];
+ class = p[skip + 2] << 8 | p[skip + 3];
+ len = p[skip + 8] << 8 | p[skip + 9];
+ p += skip + 10;
+ if (p + len > eom) {
+ errno = EMSGSIZE;
+ break;
+ }
+ /* Skip entries of the wrong class and type. */
+ if (class != qclass || type != T_TXT) {
+ p += len;
+ continue;
+ }
+ /* Allocate space for this answer. */
+ list[j] = malloc((size_t)len);
+ if (!list[j]) {
+ errno = ENOMEM;
+ break;
+ }
+ dst = list[j++];
+
+ /* Copy answer data into the allocated area. */
+ eor = p + len;
+ while (p < eor) {
+ n = (unsigned char) *p++;
+ if (p + n > eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ memcpy(dst, p, (size_t)n);
+ p += n;
+ dst += n;
+ }
+ if (p < eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ *dst = 0;
+ }
+
+ /*
+ * If we didn't terminate the loop normally, something
+ * went wrong.
+ */
+ if (i < ancount) {
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return NULL;
+ }
+ if (j == 0) {
+ errno = ENOENT;
+ free(list);
+ return NULL;
+ }
+ list[j] = NULL;
+ return list;
+}
+
+ /*
+ * COMPATIBILITY FUNCTIONS
+ */
+
+static int inited = 0;
+static void *context;
+static int errval = HES_ER_UNINIT;
+
+int
+hes_init()
+{
+ init_context();
+ return errval;
+}
+
+char *
+hes_to_bind(name, type)
+ const char *name;
+ const char *type;
+{
+ static char *bindname;
+ if (init_context() < 0)
+ return NULL;
+ if (bindname)
+ free(bindname);
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ translate_errors();
+ return bindname;
+}
+
+char **
+hes_resolve(name, type)
+ const char *name;
+ const char *type;
+{
+ static char **list;
+
+ if (init_context() < 0)
+ return NULL;
+
+ /*
+ * In the old Hesiod interface, the caller was responsible for
+ * freeing the returned strings but not the vector of strings itself.
+ */
+ if (list)
+ free(list);
+
+ list = hesiod_resolve(context, name, type);
+ if (!list)
+ translate_errors();
+ return list;
+}
+
+int
+hes_error()
+{
+ return errval;
+}
+
+void
+hes_free(hp)
+ char **hp;
+{
+ hesiod_free_list(context, hp);
+}
+
+static int
+init_context()
+{
+ if (!inited) {
+ inited = 1;
+ if (hesiod_init(&context) < 0) {
+ errval = HES_ER_CONFIG;
+ return -1;
+ }
+ errval = HES_ER_OK;
+ }
+ return 0;
+}
+
+static void
+translate_errors()
+{
+ switch (errno) {
+ case ENOENT:
+ errval = HES_ER_NOTFOUND;
+ break;
+ case ECONNREFUSED:
+ case EMSGSIZE:
+ errval = HES_ER_NET;
+ break;
+ case ENOMEM:
+ default:
+ /* Not a good match, but the best we can do. */
+ errval = HES_ER_CONFIG;
+ break;
+ }
+}
diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c
index 8edcb1b..ea08d92 100644
--- a/lib/libc/net/name6.c
+++ b/lib/libc/net/name6.c
@@ -109,6 +109,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <unistd.h>
#ifndef _PATH_HOSTS
@@ -169,110 +171,32 @@ static char *_hgetword(char **pp);
static int _mapped_addr_enabled(void);
static FILE *_files_open(int *errp);
-static struct hostent *_files_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _files_ghbyname(void *, void *, va_list);
+static int _files_ghbyaddr(void *, void *, va_list);
static void _files_shent(int stayopen);
static void _files_ehent(void);
#ifdef YP
-static struct hostent *_nis_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _nis_ghbyname(void *, void *, va_list);
+static int _nis_ghbyaddr(void *, void *, va_list);
#endif
-static struct hostent *_dns_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _dns_ghbyname(void *, void *, va_list);
+static int _dns_ghbyaddr(void *, void *, va_list);
static void _dns_shent(int stayopen);
static void _dns_ehent(void);
#ifdef ICMPNL
-static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _icmp_ghbyaddr(void *, void *, va_list);
#endif /* ICMPNL */
-/*
- * Select order host function.
- */
-#define MAXHOSTCONF 4
-
-#ifndef HOSTCONF
-# define HOSTCONF "/etc/host.conf"
-#endif /* !HOSTCONF */
-
-struct _hostconf {
- struct hostent *(*byname)(const char *name, int af, int *errp);
- struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
-};
-
-/* default order */
-static struct _hostconf _hostconf[MAXHOSTCONF] = {
- { _dns_ghbyname, _dns_ghbyaddr },
- { _files_ghbyname, _files_ghbyaddr },
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
#ifdef ICMPNL
- { NULL, _icmp_ghbyaddr },
-#endif /* ICMPNL */
-};
-
-static int _hostconf_init_done;
-static void _hostconf_init(void);
-
-/*
- * Initialize hostconf structure.
- */
-
-static void
-_hostconf_init(void)
-{
- FILE *fp;
- int n;
- char *p, *line;
- char buf[BUFSIZ];
-
- _hostconf_init_done = 1;
- n = 0;
- p = HOSTCONF;
- if ((fp = fopen(p, "r")) == NULL)
- return;
- while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
- line = buf;
- if ((p = _hgetword(&line)) == NULL)
- continue;
- do {
- if (strcmp(p, "hosts") == 0
- || strcmp(p, "local") == 0
- || strcmp(p, "file") == 0
- || strcmp(p, "files") == 0) {
- _hostconf[n].byname = _files_ghbyname;
- _hostconf[n].byaddr = _files_ghbyaddr;
- n++;
- }
- else if (strcmp(p, "dns") == 0
- || strcmp(p, "bind") == 0) {
- _hostconf[n].byname = _dns_ghbyname;
- _hostconf[n].byaddr = _dns_ghbyaddr;
- n++;
- }
-#ifdef YP
- else if (strcmp(p, "nis") == 0) {
- _hostconf[n].byname = _nis_ghbyname;
- _hostconf[n].byaddr = _nis_ghbyaddr;
- n++;
- }
+#define NSSRC_ICMP "icmp"
+ { NSSRC_ICMP, NS_SUCCESS },
#endif
-#ifdef ICMPNL
- else if (strcmp(p, "icmp") == 0) {
- _hostconf[n].byname = NULL;
- _hostconf[n].byaddr = _icmp_ghbyaddr;
- n++;
- }
-#endif /* ICMPNL */
- } while ((p = _hgetword(&line)) != NULL);
- }
- fclose(fp);
- if (n < 0) {
- /* no keyword found. do not change default configuration */
- return;
- }
- for (; n < MAXHOSTCONF; n++) {
- _hostconf[n].byname = NULL;
- _hostconf[n].byaddr = NULL;
- }
-}
+ { 0 }
+};
/*
* Check if kernel supports mapped address.
@@ -311,7 +235,14 @@ static struct hostent *
_ghbyname(const char *name, int af, int flags, int *errp)
{
struct hostent *hp;
- int i;
+ int i, rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyname, NULL)
+ { NSSRC_DNS, _dns_ghbyname, NULL },
+ NS_NIS_CB(_nis_ghbyname, NULL)
+ { 0 }
+ };
if (flags & AI_ADDRCONFIG) {
int s;
@@ -342,13 +273,9 @@ _ghbyname(const char *name, int af, int flags, int *errp)
}
}
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (_hostconf[i].byname
- && (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL)
- return hp;
- }
-
- return NULL;
+ rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
+ name, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
}
/* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
@@ -392,9 +319,6 @@ _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
return _hpaddr(af, name, &addrbuf, errp);
}
- if (!_hostconf_init_done)
- _hostconf_init();
-
*errp = HOST_NOT_FOUND;
hp = _ghbyname(name, af, flags, errp);
@@ -436,13 +360,23 @@ struct hostent *
getipnodebyaddr(const void *src, size_t len, int af, int *errp)
{
struct hostent *hp;
- int i;
+ int i, rval;
#ifdef INET6
struct in6_addr addrbuf;
#else
struct in_addr addrbuf;
#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyaddr, NULL)
+ { NSSRC_DNS, _dns_ghbyaddr, NULL },
+ NS_NIS_CB(_nis_ghbyaddr, NULL)
+#ifdef ICMPNL
+ { NSSRC_ICMP, _icmp_ghbyaddr, NULL },
+#endif
+ { 0 }
+ };
+
*errp = HOST_NOT_FOUND;
switch (af) {
@@ -484,15 +418,9 @@ getipnodebyaddr(const void *src, size_t len, int af, int *errp)
return NULL;
}
- if (!_hostconf_init_done)
- _hostconf_init();
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (_hostconf[i].byaddr
- && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
- return hp;
- }
-
- return NULL;
+ rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
+ src, len, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
}
void
@@ -828,9 +756,12 @@ _files_open(int *errp)
return fp;
}
-static struct hostent *
-_files_ghbyname(const char *name, int af, int *errp)
+static int
+_files_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
int match, nalias;
char *p, *line, *addrstr, *cname;
FILE *fp;
@@ -840,8 +771,14 @@ _files_ghbyname(const char *name, int af, int *errp)
char buf[BUFSIZ];
int af0 = af;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
if ((fp = _files_open(errp)) == NULL)
- return NULL;
+ return NS_UNAVAIL;
rethp = hp = NULL;
while (fgets(buf, sizeof(buf), fp)) {
@@ -906,12 +843,17 @@ _files_ghbyname(const char *name, int af, int *errp)
rethp = _hpmerge(rethp, hp, errp);
}
fclose(fp);
- return rethp;
+ *(struct hostent **)rval = rethp;
+ return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_files_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
int nalias;
char *p, *line;
FILE *fp;
@@ -920,8 +862,15 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
union inx_addr addrbuf;
char buf[BUFSIZ];
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent**)rval = NULL;
+
if ((fp = _files_open(errp)) == NULL)
- return NULL;
+ return NS_UNAVAIL;
hp = NULL;
while (fgets(buf, sizeof(buf), fp)) {
line = buf;
@@ -950,7 +899,8 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
break;
}
fclose(fp);
- return hp;
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#ifdef YP
@@ -959,11 +909,18 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
*
* XXX actually a hack, these are INET4 specific.
*/
-static struct hostent *
-_nis_ghbyname(const char *name, int af, int *errp)
+static int
+_nis_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
struct hostent *hp = NULL;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
if (af == AF_UNSPEC)
af = AF_INET;
if (af == AF_INET) {
@@ -971,21 +928,32 @@ _nis_ghbyname(const char *name, int af, int *errp)
if (hp != NULL)
hp = _hpcopy(hp, errp);
}
- return (hp);
+
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
struct hostent *hp = NULL;
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+
if (af == AF_INET) {
hp = _gethostbynisaddr(addr, addrlen, af);
if (hp != NULL)
hp = _hpcopy(hp, errp);
}
- return (hp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#endif
@@ -1486,14 +1454,21 @@ _res_search_multi(name, rtl, errp)
return (NULL);
}
-static struct hostent *
-_dns_ghbyname(const char *name, int af, int *errp)
+static int
+_dns_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
struct __res_type_list *rtl, rtl4;
#ifdef INET6
struct __res_type_list rtl6;
#endif
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
#ifdef INET6
switch (af) {
case AF_UNSPEC:
@@ -1514,12 +1489,17 @@ _dns_ghbyname(const char *name, int af, int *errp)
SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
rtl = &rtl4;
#endif
- return(_res_search_multi(name, rtl, errp));
+ *(struct hostent **)rval = _res_search_multi(name, rtl, errp);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
int n;
struct hostent *hp;
u_char c, *cp;
@@ -1533,16 +1513,23 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
char qbuf[MAXDNAME+1];
char *hlist[2];
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
#ifdef INET6
/* XXX */
if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
- return NULL;
+ return NS_NOTFOUND;
#endif
if ((_res.options & RES_INIT) == 0) {
if (res_init() < 0) {
*errp = h_errno;
- return NULL;
+ return NS_UNAVAIL;
}
}
memset(&hbuf, 0, sizeof(hbuf));
@@ -1585,17 +1572,18 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
if (n < 0) {
*errp = h_errno;
- return NULL;
+ return NS_UNAVAIL;
}
hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp);
if (!hp)
- return NULL;
+ return NS_NOTFOUND;
hbuf.h_addrtype = af;
hbuf.h_length = addrlen;
hbuf.h_addr_list = hlist;
hlist[0] = (char *)addr;
hlist[1] = NULL;
- return _hpcopy(&hbuf, errp);
+ *(struct hostent **)rval = _hpcopy(&hbuf, errp);
+ return NS_SUCCESS;
}
static void
diff --git a/lib/libc/net/nsdispatch.3 b/lib/libc/net/nsdispatch.3
new file mode 100644
index 0000000..bd6366e
--- /dev/null
+++ b/lib/libc/net/nsdispatch.3
@@ -0,0 +1,231 @@
+.\" $NetBSD: nsdispatch.3,v 1.8 1999/03/22 19:44:53 garbled Exp $
+.\" $FreeBSD$
+.\"
+.\" 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
+.Fx 4.1 .
+They were imported from the
+.Nx
+Project,
+where they appeared first in
+.Nx 1.4 .
+.Sh AUTHORS
+Luke Mewburn
+.Aq lukem@netbsd.org
+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 --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
new file mode 100644
index 0000000..311b89d
--- /dev/null
+++ b/lib/libc/net/nsdispatch.c
@@ -0,0 +1,270 @@
+/* $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)
+static char *rcsid =
+ "$FreeBSD$";
+#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>
+
+/*
+ * 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 --git a/lib/libc/net/nslexer.l b/lib/libc/net/nslexer.l
new file mode 100644
index 0000000..104cfbb
--- /dev/null
+++ b/lib/libc/net/nslexer.l
@@ -0,0 +1,116 @@
+%{
+/* $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)
+static char *rcsid =
+ "$FreeBSD$";
+#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 --git a/lib/libc/net/nsparser.y b/lib/libc/net/nsparser.y
new file mode 100644
index 0000000..b39f011
--- /dev/null
+++ b/lib/libc/net/nsparser.y
@@ -0,0 +1,175 @@
+%{
+/* $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)
+static char *rcsid =
+ "$FreeBSD$";
+#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);
+}
diff --git a/release/sysinstall/installUpgrade.c b/release/sysinstall/installUpgrade.c
index 1c70020..f82bfb7 100644
--- a/release/sysinstall/installUpgrade.c
+++ b/release/sysinstall/installUpgrade.c
@@ -78,7 +78,6 @@ static HitList etc_files [] = {
{ JUST_COPY, "gettytab", TRUE, NULL },
{ JUST_COPY, "gnats", TRUE, NULL },
{ JUST_COPY, "group", FALSE, NULL },
- { JUST_COPY, "host.conf", TRUE, NULL },
{ JUST_COPY, "hosts", TRUE, NULL },
{ JUST_COPY, "hosts.equiv", TRUE, NULL },
{ JUST_COPY, "hosts.lpd", TRUE, NULL },
@@ -96,6 +95,7 @@ static HitList etc_files [] = {
{ JUST_COPY, "namedb", TRUE, NULL },
{ JUST_COPY, "networks", TRUE, NULL },
{ JUST_COPY, "newsyslog.conf", TRUE, NULL },
+ { JUST_COPY, "nsswitch.conf", TRUE, NULL },
{ JUST_COPY, "pam.conf", TRUE, NULL },
{ JUST_COPY, "passwd", TRUE, NULL },
{ JUST_COPY, "periodic", TRUE, NULL },
diff --git a/release/texts/UPGRADE.TXT b/release/texts/UPGRADE.TXT
index ae5d123..ec5b565 100644
--- a/release/texts/UPGRADE.TXT
+++ b/release/texts/UPGRADE.TXT
@@ -62,17 +62,16 @@ the old distribution are not deleted.
System configuration is preserved by retaining and restoring the
previous version of the following files:
- Xaccel.ini, XF86Config, adduser.conf, aliases, aliases.db, amd.map,
- aliases, aliases.db, auth.conf, crontab, csh.cshrc, csh.login,
- csh.logout, cvsupfile, disktab, dm.conf, dumpdates, exports,
- fbtab, fstab, ftpusers, gettytab, gnats, group, host.conf, hosts,
- hosts.equiv, hosts.lpd, inetd.conf, kerberosIV, localtime, login.access,
- login.conf, mail.rc, make.conf, manpath.config, master.passwd, modems,
- motd, namedb, networks, newsyslog.conf, pam.conf, passwd, periodic,
- phones, ppp, printcap, profile, protocols, pwd.db, rc.conf.local,
- rc.firewall, rc.local, remote, resolv.conf, rmt, sendmail.cf,
- sendmail.cw, services, shells, skeykeys, spwd.db, syslog.conf,
- ttys, uucp
+ Xaccel.ini, adduser.conf, aliases, aliases.db, amd.map, crontab,
+ csh.cshrc, csh.login, csh.logout, daily, disktab, dm.conf, exports,
+ fbtab, fstab, ftpusers, gettytab, gnats, group, hosts, hosts.equiv,
+ hosts.lpd, inetd.conf, kerberosIV, localtime, login.access,
+ mail.rc, make.conf, manpath.config, master.passwd, mib.txt, modems,
+ monthly, motd, namedb, networks, nsswitch.conf, passwd, phones,
+ ppp, printcap, profile, protocols, pwd.db, rc, rc.firewall,
+ rc.i386, rc.local, rc.network, rc.conf, remote, resolv.conf, rmt,
+ security, sendmail.cf, services, shells, skeykeys, spwd.db,
+ supfile, syslog.conf, termcap, ttys, uucp, weekly
The versions of these files which correspond to the new version are
moved to /etc/upgrade/. The system administrator may peruse these new
diff --git a/sbin/dhclient/Makefile b/sbin/dhclient/Makefile
index b6a73e8..a88f532 100644
--- a/sbin/dhclient/Makefile
+++ b/sbin/dhclient/Makefile
@@ -11,7 +11,7 @@ SRCS+= alloc.c bpf.c conflex.c convert.c dispatch.c errwarn.c ethernet.c \
parse.c print.c raw.c socket.c tables.c tree.c upf.c
CFLAGS+= -I${DIST_DIR}/includes -I${DIST_DIR}
-CFLAGS+= -DCLIENT_PATH='"PATH=/sbin:/bin:/usr/sbin:/usr/bin"'
+CFLAGS+= -DCLIENT_PATH='"PATH=/sbin:/bin:/usr/sbin:/usr/bin"' -Dwarn=dhcp_warn
MAN5= dhclient.conf.5 dhclient.leases.5 dhcp-options.5
MAN8= dhclient.8 dhclient-script.8
diff --git a/share/examples/etc/README.examples b/share/examples/etc/README.examples
index 2bcd4b0..a2739b3 100644
--- a/share/examples/etc/README.examples
+++ b/share/examples/etc/README.examples
@@ -20,7 +20,6 @@ fbtab - configuration file for login(1)
ftpusers - user restriction file for ftpd(8)
gettytab - defines port configuration for getty(8)
group - group permissions file (see group(5))
-host.conf - defines name resolution order for gethostbyname(3)
hosts - see hosts(5)
hosts.equiv - defines system-wide trusted hosts (see ruserok(3))
hosts.lpd - defines trusted hosts for lpd(8)
@@ -36,6 +35,7 @@ motd - sample Message of the Day
netstart - network startup script run from /etc/rc
networks - see networks(5)
newsyslog.conf - configuration for system log file rotator newsyslog(8)
+nsswitch.conf - name-service switch config file (see nsswitch.conf(5))
pam.conf - configuration file for pam(8)
pccard_ether - confiuration script for ethernet pccards (see pccardd(8))
phones - phone number database for tip(1)
diff --git a/share/man/man4/yp.4 b/share/man/man4/yp.4
index dda8944..3ceab06 100644
--- a/share/man/man4/yp.4
+++ b/share/man/man4/yp.4
@@ -57,14 +57,8 @@ daemon makes direct
library calls since there are no
functions in the standard C library for reading bootparams.
.Tn NIS
-support for the hosts, services and rpc databases is enabled by
-uncommenting the
-.Em nis
-line in
-.Pa /etc/host.conf .
-.Tn NIS
-support for the remaining services is
-activated by adding a special '+' entry to the appropriate file.
+support is enabled in
+.Xr nsswitch.conf .
.Pp
The
.Nm YP
diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile
index 83fc325..a16b1c1 100644
--- a/share/man/man5/Makefile
+++ b/share/man/man5/Makefile
@@ -4,11 +4,12 @@
#MISSING: dump.5 plot.5
MAN5= a.out.5 acct.5 core.5 devfs.5 dir.5 disktab.5 ethers.5 \
elf.5 fbtab.5 fdesc.5 forward.5 fs.5 fstab.5 group.5 \
+ hesiod.conf.5 \
hosts.5 hosts.equiv.5 hosts.lpd.5 intro.5 kernfs.5 link.5 \
- linprocfs.5 mailer.conf.5 motd.5 networks.5 passwd.5 pbm.5 \
- periodic.conf.5 phones.5 procfs.5 protocols.5 rc.conf.5 \
- remote.5 resolver.5 services.5 shells.5 stab.5 sysctl.conf.5 \
- types.5 utmp.5
+ linprocfs.5 mailer.conf.5 motd.5 networks.5 nsswitch.conf.5 \
+ passwd.5 pbm.5 periodic.conf.5 \
+ phones.5 procfs.5 protocols.5 rc.conf.5 remote.5 resolver.5 \
+ services.5 shells.5 stab.5 sysctl.conf.5 types.5 utmp.5
MLINKS= dir.5 dirent.5
MLINKS+=fs.5 inode.5
diff --git a/share/man/man5/group.5 b/share/man/man5/group.5
index 764caf5..5df3e04 100644
--- a/share/man/man5/group.5
+++ b/share/man/man5/group.5
@@ -39,6 +39,14 @@
.Nm group
.Nd format of the group permissions file
.Sh DESCRIPTION
+The
+.Nm
+file is the local source of group information. It
+can be used in conjunction with the Hesiod domain
+`group', and the NIS maps `group.byname' and `group.bygid',
+as controlled by
+.Xr nsswitch.conf 5 .
+.Pp
The file
.Aq Pa /etc/group
consists of newline separated
@@ -107,28 +115,6 @@ entry and does not need to be added to that group in the
.\" char **gr_mem; /* group members */
.\" };
.\" .Ed
-.Sh YP/NIS INTERACTION
-The
-.Pa /etc/group
-file can be configured to enable the YP/NIS group database.
-An entry whose
-.Ar name
-field consists of a plus sign (`+') followed by a group name, will be
-replaced internally to the C library with the YP/NIS group entry for the
-named group. An entry whose
-.Ar name
-field consists of a single plus sign with no group name following,
-will be replaced with the entire YP/NIS
-.Dq Li group.byname
-map.
-.Pp
-If the YP/NIS group database is enabled for any reason, all reverse
-lookups (i.e.,
-.Fn getgrgid )
-will use the entire database, even if only a few groups are enabled.
-Thus, the group name returned by
-.Fn getgrgid
-is not guaranteed to have a valid forward mapping.
.Sh LIMITS
There are various limitations which are explained in
the function where they occur; see section
@@ -156,6 +142,7 @@ may still have this limits.
.Xr getgrent 3 ,
.Xr initgroups 3 ,
.Xr yp 4 ,
+.Xr nsswitch.conf 5 ,
.Xr passwd 5
.Sh BUGS
The
@@ -168,10 +155,5 @@ A
.Nm
file format appeared in
.At v6 .
-The YP/NIS functionality is modeled after
-.Tn SunOS
-and first appeared in
-.Tn FreeBSD
-1.1.
Support for comments first appeared in
.Fx 3.0 .
diff --git a/share/man/man5/hesiod.conf.5 b/share/man/man5/hesiod.conf.5
new file mode 100644
index 0000000..639b447
--- /dev/null
+++ b/share/man/man5/hesiod.conf.5
@@ -0,0 +1,53 @@
+.\" $NetBSD: hesiod.conf.5,v 1.2 1999/01/25 22:37:06 lukem Exp $
+.\" $FreeBSD$
+.\"
+.\" from: #Id: hesiod.conf.5,v 1.1 1996/12/08 21:36:38 ghudson Exp #
+.\"
+.\" Copyright 1996 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.TH HESIOD.CONF 5 "30 November 1996"
+.SH NAME
+hesiod.conf \- Configuration file for the Hesiod library
+.SH DESCRIPTION
+The file hesiod.conf determines the behavior of the Hesiod library.
+Blank lines and lines beginning with a `#' character are ignored. All
+other lines should be of the form
+.I variable
+=
+.IR value ,
+where the value should be a single word. Possible variables and
+values are:
+.IP lhs
+Specifies the domain prefix used for Hesiod queries. In almost all
+cases, you should specify ``lhs=.ns''. The default value if you do
+not specify an lhs value is no domain prefix, which is not compatible
+with most Hesiod domains.
+.IP rhs
+Specifies the default Hesiod domain; this value may be overridden by
+the
+.B HES_DOMAIN
+environment variable. You must specify an rhs line for the Hesiod
+library to work properly.
+.IP classes
+Specifies which DNS classes Hesiod should do lookups in. Possible
+values are IN (the preferred class) and HS (the deprecated class,
+still used by some sites). You may specify both classes separated by
+a comma to try one class first and then the other if no entry is
+available in the first class. The default value of the classes
+variable is ``IN,HS''.
+.SH SEE ALSO
+hesiod(3)
+.SH BUGS
+The default value for ``lhs'' should probably be more reasonable.
diff --git a/share/man/man5/hosts.5 b/share/man/man5/hosts.5
index 00ca8ce..3708958 100644
--- a/share/man/man5/hosts.5
+++ b/share/man/man5/hosts.5
@@ -43,6 +43,9 @@ The
.Nm hosts
file contains information regarding
the known hosts on the network.
+It can be used in conjunction with DNS, and the NIS
+maps `hosts.byaddr' and `hosts.byname', as controlled by
+.Xr nsswitch.conf 5 .
For each host a single line should be present
with the following information:
.Bd -unfilled -offset indent
@@ -98,6 +101,7 @@ file resides in
.El
.Sh SEE ALSO
.Xr gethostbyname 3 ,
+.Xr nsswitch.conf 5 ,
.Xr ifconfig 8 ,
.Xr named 8
.Rs
diff --git a/share/man/man5/nsswitch.conf.5 b/share/man/man5/nsswitch.conf.5
new file mode 100644
index 0000000..ca281c8
--- /dev/null
+++ b/share/man/man5/nsswitch.conf.5
@@ -0,0 +1,266 @@
+.\" $NetBSD: nsswitch.conf.5,v 1.14 1999/03/17 20:19:47 garbled Exp $
+.\" $FreeBSD$
+.\"
+.\" 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, 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 "networks" -offset indent -compact
+.Sy Database Used by
+.It group
+.Xr getgrent 3
+.It hosts
+.Xr gethostbyname 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 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
+.Fx 4.1 .
+It was imported from the
+.Nx
+Project, where it appeared first in
+.Nx 1.4 .
+.Sh AUTHORS
+Luke Mewburn
+.Aq lukem@netbsd.org
+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.
diff --git a/share/man/man5/passwd.5 b/share/man/man5/passwd.5
index 51b1c3b..671d42b 100644
--- a/share/man/man5/passwd.5
+++ b/share/man/man5/passwd.5
@@ -1,5 +1,8 @@
+.\" $NetBSD: passwd.5,v 1.12.2.2 1999/12/17 23:14:50 he Exp $
+.\"
.\" Copyright (c) 1988, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
+.\" Portions Copyright (c) 1994, Jason Downs. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -32,20 +35,37 @@
.\" From: @(#)passwd.5 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd September 29, 1994
+.Dd January 16, 1999
.Dt PASSWD 5
.Os
.Sh NAME
-.Nm passwd
+.Nm passwd ,
+.Nm master.passwd
.Nd format of the password file
.Sh DESCRIPTION
The
.Nm passwd
-files are files consisting of newline separated records, one per user,
-containing ten colon
-.Pq Ql \&:
-separated fields. These fields are as
-follows:
+files are the local source of password information.
+They can be used in conjunction with the Hesiod domains
+.Sq passwd
+and
+.Sq uid ,
+and the
+.Tn NIS
+maps
+.Sq passwd.byname ,
+.Sq passwd.byuid ,
+.Sq master.passwd.byname ,
+and
+.Sq master.passwd.byuid ,
+as controlled by
+.Xr nsswitch.conf 5 .
+.Pp
+The
+.Nm master.passwd
+file is readable only by root, and consists of newline separated
+records, one per user, containing ten colon (``:'') separated
+fields. These fields are as follows:
.Pp
.Bl -tag -width password -offset indent
.It name
@@ -59,7 +79,7 @@ User's id.
.It gid
User's login group id.
.It class
-User's login class.
+User's general classification (unused).
.It change
Password change time.
.It expire
@@ -72,9 +92,14 @@ User's home directory.
User's login shell.
.El
.Pp
-Lines whose first non-whitespace character is a pound-sign (#)
-are comments, and are ignored. Blank lines which consist
-only of spaces, tabs or newlines are also ignored.
+The
+.Nm
+file is generated from the
+.Nm master.password
+file by
+.Xr pwd_mkdb 8 ,
+has the class, change, and expire fields removed, and the password
+field replaced by a ``*''.
.Pp
The
.Ar name
@@ -85,17 +110,15 @@ across the system (and often across a group of systems) since they
control file access.
.Pp
While it is possible to have multiple entries with identical login names
-and/or identical uids, it is usually a mistake to do so. Routines
+and/or identical user id's, it is usually a mistake to do so. Routines
that manipulate these files will often return only one of the multiple
entries, and that one by random selection.
.Pp
-The login name must never begin with a hyphen
-.Pq Ql \&- ;
-also, it is strongly
-suggested that neither upper-case characters nor dots
-.Pq Ql \&.
-be part
-of the name, as this tends to confuse mailers.
+The login name must never begin with a hyphen (``-''); also, it is strongly
+suggested that neither upper-case characters or dots (``.'') be part
+of the name, as this tends to confuse mailers. No field may contain a
+colon (``:'') as this has been used historically to separate the fields
+in the user database.
.Pp
The password field is the
.Em encrypted
@@ -106,73 +129,66 @@ field is empty, no password will be required to gain access to the
machine. This is almost invariably a mistake.
Because these files contain the encrypted user passwords, they should
not be readable by anyone without appropriate privileges.
-Administrative accounts have a password field containing an asterisk
-.Ql \&*
-which disallows normal logins.
.Pp
The group field is the group that the user will be placed in upon login.
-Although this system supports multiple groups (see
+Since this system supports multiple groups (see
.Xr groups 1 )
-this field indicates the user's primary group.
-Secondary group memberships are selected in
-.Pa /etc/group .
+this field currently has little special meaning.
.Pp
The
.Ar class
-field is a key for a user's login class.
-Login classes are defined in
+field is a key for a user's login class. Login classes
+are defined in
.Xr login.conf 5 ,
-which is a
+which is a
.Xr termcap 5
-style database of user attributes, accounting, resource and
-environment settings.
+style database of user attributes, accounting, resource,
+and environment settings.
.Pp
The
.Ar change
-field is the number in seconds,
-.Dv GMT ,
-from the epoch, until the
+field is the number of seconds from the epoch,
+.Dv UTC ,
+until the
password for the account must be changed.
-This field may be left empty or set to 0 to turn off the
-password aging feature.
+This field may be left empty to turn off the password aging feature.
.Pp
The
.Ar expire
-field is the number in seconds,
-.Dv GMT ,
-from the epoch, until the
+field is the number of seconds from the epoch,
+.Dv UTC ,
+until the
account expires.
-This field may be left empty or set to 0 to turn off the account
-aging feature.
+This field may be left empty to turn off the account aging feature.
.Pp
The
.Ar gecos
-field normally contains comma
-.Pq Ql \&,
-separated subfields as follows:
+field normally contains comma (``,'') separated subfields as follows:
.Pp
-.Bl -bullet -compact -offset indent
-.It
+.Bl -tag -width office -offset indent -compact
+.It name
user's full name
-.It
-user's office location
-.It
+.It office
+user's office number
+.It wphone
user's work phone number
-.It
+.It hphone
user's home phone number
.El
.Pp
-This information is used by the
+The full name may contain a ampersand (``&'') which will be replaced by
+the capitalized login name when the gecos field is displayed or used
+by various programs such as
+.Xr finger 1 ,
+.Xr sendmail 8 ,
+etc.
+.Pp
+The office and phone number subfields are used by the
.Xr finger 1
-program, and the first field used by the system mailer.
-If an ampersand
-.Pq Ql \&&
-character appears within the fullname field, programs that
-use this field will substitute it with a capitalized version
-of the account's login name.
+program, and possibly other applications.
.Pp
The user's home directory is the full
-.Tn UNIX
+.Ux
path name where the user
will be placed on login.
.Pp
@@ -182,589 +198,119 @@ If there is nothing in the
field, the Bourne shell
.Pq Pa /bin/sh
is assumed.
-For security reasons, if the shell is set to a script that disallows
-access to the system (the
-.Xr nologin 8
-script, for example), care should be taken not to import any environment
-variables. With
-.Xr sh 1 ,
-this can be done by specifying the
-.Fl p
-flag.
-Check the specific shell documentation to determine how this is
-done with other shells.
-.Sh YP/NIS INTERACTION
-.Ss Enabling access to NIS passwd data
-The system administrator can configure
-.Tn FreeBSD
-to use NIS/YP for
-its password information by adding special records to the
-.Pa /etc/master.passwd
-file.
-These entries should be added with
-.Xr vipw 8
-so that the changes can be properly merged with the hashed
-password databases and the
-.Pa /etc/passwd
-file (
-.Pa /etc/passwd
-should never be edited manually). Alternatively, the administrator
-can modify
-.Pa /etc/master.passwd
-in some other way and then manually update the password databases with
-.Xr pwd_mkdb 8 .
-.Pp
-The simplest way to activate NIS is to add an empty record
-with only a plus sign
-.Pq Ql \&+
-in the name field, such as this:
-.Bd -literal -offset indent
-+:::::::::
-
-.Ed
-The
-.Ql \&+
-will tell the
-.Xr getpwent 3
-routines in
-.Tn FreeBSD Ns 's
-standard C library to begin using the NIS passwd maps
-for lookups.
-.Pp
-Note that the entry shown above is known as a
-.Em wildcard
-entry, because it matches all users (the
-.Ql \&+
-without any other information
-matches everybody) and allows all NIS password data to be retrieved
-unaltered.
-However, by
-specifying a username or netgroup next to the
-.Ql \&+
-in the NIS
-entry, the administrator can affect what data are extracted from the
-NIS passwd maps and how it is interpreted.
-Here are a few example
-records that illustrate this feature (note that you can have several
-NIS entries in a single
-.Pa master.passwd
-file):
-.Bd -literal -offset indent
--mitnick:::::::::
-+@staff:::::::::
-+@permitted-users:::::::::
-+dennis:::::::::
-+ken:::::::::/bin/csh
-+@rejected-users::32767:32767::::::/bin/false
-
-.Ed
-Specific usernames are listed explicitly while netgroups are signified
-by a preceding
-.Ql \&@ .
-In the above example, users in the
-.Dq staff
-and
-.Dq permitted-users
-netgroups will have their password information
-read from NIS and used unaltered.
-In other words, they will be allowed
-normal access to the machine.
-Users
-.Dq ken
-and
-.Dq dennis ,
-who have
-been named explicitly rather than through a netgroup, will also have
-their password data read from NIS,
-.Em except
-that user
-.Dq ken
-will have his shell remapped to
-.Pa /bin/csh .
-This means that value for his shell specified in the NIS password map
-will be overridden by the value specified in the special NIS entry in
-the local
-.Pa master.passwd
-file.
-User
-.Dq ken
-may have been assigned the csh shell because his
-NIS password entry specified a different shell that may not be
-installed on the client machine for political or technical reasons.
-Meanwhile, users in the
-.Dq rejected-users
-netgroup are prevented
-from logging in because their UIDs, GIDs and shells have been overridden
-with invalid values.
-.Pp
-User
-.Dq mitnick
-will be be ignored entirely because his entry is
-specified with a
-.Ql \&-
-instead of a
-.Ql \&+ .
-A minus entry can be used
-to block out certain NIS password entries completely; users whose
-password data has been excluded in this way are not recognized by
-the system at all.
-(Any overrides specified with minus entries are
-also ignored since there is no point in processing override information
-for a user that the system isn't going to recognize in the first place.)
-In general, a minus entry is used to specifically exclude a user
-who might otherwise be granted access because he happens to be a
-member of an authorized netgroup.
-For example, if
-.Dq mitnick
-is
-a member of the
-.Dq permitted-users
-netgroup and must, for whatever
-the reason, be permitted to remain in that netgroup (possibly to
-retain access to other machines within the domain), the administrator
-can still deny him access to a particular system with a minus entry.
-Also, it is sometimes easier to explicitly list those users who are not
-allowed access rather than generate a possibly complicated list of
-users who are allowed access and omit the rest.
-.Pp
-Note that the plus and minus entries are evaluated in order from
-first to last with the first match taking precedence.
-This means
-the system will only use the first entry that matches a particular user.
-If, using the same example, there is a user
-.Dq foo
-who is a member of both the
-.Dq staff
-netgroup and the
-.Dq rejected-users
-netgroup, he will be admitted to
-the system because the above example lists the entry for
-.Dq staff
-before the entry for
-.Dq rejected-users .
-If the order were reversed,
-user
-.Dq foo
-would be flagged as a
-.Dq rejected-user
-instead and denied access.
-.Pp
-Lastly, any NIS password database records that do not match against
-at least one of the users or netgroups specified by the NIS access
-entries in the
-.Pa /etc/master.passwd
-file will be ignored (along with any users specified using minus
-entries). In our example shown above, we do not have a wildcard
-entry at the end of the list; therefore, the system will not recognize
-anyone except
-.Dq ken ,
-.Dq dennis ,
-the
-.Dq staff
-netgroup, and the
-.Dq permitted-users
-netgroup as authorized users.
-The
-.Dq rejected-users
-netgroup will
-be recognized but all members will have their shells remapped and
-therefore be denied access.
-All other NIS password records
-will be ignored.
-The administrator may add a wildcard entry to the
-end of the list such as:
-.Bd -literal -offset indent
-+:::::::::/sbin/nologin
-
-.Ed
-This entry acts as a catch-all for all users that don't match against
-any of the other entries.
-This technique is sometimes useful when it is
-desirable to have the system be able to recognize all users in a
-particular NIS domain without necessarily granting them login access.
-See the description of the shell field regarding security concerns when using
-a shell script as the login shell.
-.Pp
-The primary use of this
-.Pa override
-feature is to permit the administrator
-to enforce access restrictions on NIS client systems.
-Users can be
-granted access to one group of machines and denied access to other
-machines simply by adding or removing them from a particular netgroup.
-Since the netgroup database can also be accessed via NIS, this allows
-access restrictions to be administered from a single location, namely
-the NIS master server; once a host's access list has been set in
-.Pa /etc/master.passwd ,
-it need not be modified again unless new netgroups are created.
-.Sh NOTES
-.Ss Shadow passwords through NIS
-.Tn FreeBSD
-uses a shadow password scheme: users' encrypted passwords
-are stored only in
-.Pa /etc/master.passwd
-and
-.Pa /etc/spwd.db ,
-which are readable and writable only by the superuser.
-This is done
-to prevent users from running the encrypted passwords through
-password-guessing programs and gaining unauthorized access to
-other users' accounts.
-NIS does not support a standard means of
-password shadowing, which implies that placing your password data
-into the NIS passwd maps totally defeats the security of
-.Tn FreeBSD Ns 's
-password shadowing system.
-.Pp
-.Tn FreeBSD
-provides a few special features to help get around this
-problem.
-It is possible to implement password shadowing between
-.Tn FreeBSD
-NIS clients and
-.Tn FreeBSD
-NIS servers.
-The
-.Xr getpwent 3
-routines will search for a
-.Pa master.passwd.byname
-and
-.Pa master.passwd.byuid
-maps which should contain the same data found in the
-.Pa /etc/master.passwd
-file.
-If the maps exist,
-.Tn FreeBSD
-will attempt to use them for user
-authentication instead of the standard
-.Pa passwd.byname
-and
-.Pa passwd.byuid
-maps.
-.Tn FreeBSD Ns 's
-.Xr ypserv 8
-will also check client requests to make sure they originate on a
-privileged port.
-Since only the superuser is allowed to bind to
-a privileged port, the server can tell if the requesting user
-is the superuser; all requests from non-privileged users to access
-the
-.Pa master.passwd
-maps will be refused.
-Since all user authentication programs run
-with superuser privilege, they should have the required access to
-users' encrypted password data while normal users will only
-be allowed access to the standard
-.Pa passwd
-maps which contain no password information.
-.Pp
-Note that this feature cannot be used in an environment with
-.No non- Ns Tn FreeBSD
-systems.
-Note also that a truly determined user with
-unrestricted access to your network could still compromise the
-.Pa master.passwd
+.Sh HESIOD SUPPORT
+If
+.Sq dns
+is specified for the
+.Sq passwd
+database in
+.Xr nsswitch.conf 5 ,
+then
+.Nm
+lookups occur from the
+.Sq passwd
+Hesiod domain.
+.Sh NIS SUPPORT
+If
+.Sq nis
+is specified for the
+.Sq passwd
+database in
+.Xr nsswitch.conf 5 ,
+then
+.Nm
+lookups occur from the
+.Sq passwd.byname ,
+.Sq passwd.byuid ,
+.Sq master.passwd.byname ,
+and
+.Sq master.passwd.byuid
+.Tn NIS
maps.
-.Ss UID and GID remapping with NIS overrides
-Unlike
-.Tn SunOS
-and other operating systems that use Sun's NIS code,
-.Tn FreeBSD
-allows the user to override
-.Pa all
-of the fields in a user's NIS
-.Pa passwd
-entry.
-For example, consider the following
-.Pa /etc/master.passwd
-entry:
-.Bd -literal -offset indent
-+@foo-users:???:666:666:0:0:0:Bogus user:/home/bogus:/bin/bogus
-
-.Ed
-This entry will cause all users in the `foo-users' netgroup to
-have
-.Pa all
-of their password information overridden, including UIDs,
-GIDs and passwords.
-The result is that all `foo-users' will be
-locked out of the system, since their passwords will be remapped
-to invalid values.
-.Pp
-This is important to remember because most people are accustomed to
-using an NIS wildcard entry that looks like this:
-.Bd -literal -offset indent
-+:*:0:0:::
-
-.Ed
-This often leads to new
-.Tn FreeBSD
-administrators choosing NIS entries for their
-.Pa master.passwd
-files that look like this:
-.Bd -literal -offset indent
-+:*:0:0::::::
-
-.Ed
-Or worse, this
-.Bd -literal -offset indent
-+::0:0::::::
-
-.Ed
-.Sy DO _NOT_ PUT ENTRIES LIKE THIS IN YOUR
-.Sy Pa master.passwd
-.Sy FILE!!
-The first tells
-.Tn FreeBSD
-to remap all passwords to
-.Ql \&*
-(which
-will prevent anybody from logging in) and to remap all UIDs and GIDs
-to 0 (which will make everybody appear to be the superuser). The
-second case just maps all UIDs and GIDs to 0, which means that
-all users will appear to be root!
-.Pp
-.Ss Compatibility of NIS override evaluation
-When Sun originally added NIS support to their
-.Xr getpwent 3
-routines, they took into account the fact that the
-.Tn SunOS
-password
-.Pa /etc/passwd
-file is in plain
-.Tn ASCII
-format.
-The
-.Tn SunOS
-documentation claims that
-adding a
-.Ql \&+
-entry to the password file causes the contents of
-the NIS password database to be
-.Dq inserted
-at the position in the file where the
-.Ql \&+
-entry appears.
-If, for example, the
-administrator places a
-.Ql \&+::::::
-entry in the middle of
-.Pa /etc/passwd ,
-then the entire contents of the NIS password map would appear
-as though it had been copied into the middle of the password
-file.
-If the administrator places
-.Ql \&+::::::
-entries at both the middle and the end of
-.Pa /etc/passwd ,
-then the NIS password map would appear twice: once in the middle
-of the file and once at the end.
-(By using override entries
-instead of simple wildcards, other combinations could be achieved.)
-.Pp
-By contrast,
-.Fx
-does not have a single
-.Tn ASCII
-password file: it
-has a hashed password database.
-This database does not have an
-easily-defined beginning, middle or end, which makes it very hard
-to design a scheme that is 100% compatible with
-.Tn SunOS .
-For example,
-the
-.Fn getpwnam
-and
-.Fn getpwuid
-functions in
-.Tn FreeBSD
-are designed to do direct queries to the
-hash database rather than a linear search.
-This approach is faster
-on systems where the password database is large.
-However, when
-using direct database queries, the system does not know or care
-about the order of the original password file, and therefore
-it cannot easily apply the same override logic used by
-.Tn SunOS .
+.Sh COMPAT SUPPORT
+If
+.Sq compat
+is specified for the
+.Sq passwd
+database, and either
+.Sq dns
+or
+.Sq nis
+is specified for the
+.Sq passwd_compat
+database in
+.Xr nsswitch.conf 5 ,
+then the
+.Nm
+file also supports standard
+.Sq +/-
+exclusions and inclusions, based on user names and netgroups.
.Pp
-Instead,
-.Tn FreeBSD
-groups all the NIS override entries together
-and constructs a filter out of them.
-Each NIS password entry
-is compared against the override filter exactly once and
-treated accordingly: if the filter allows the entry through
-unaltered, it's treated unaltered; if the filter calls for remapping
-of fields, then fields are remapped; if the filter calls for
-explicit exclusion (i.e., the entry matches a
-.Ql \&-
-override), the entry is ignored; if the entry doesn't match against any
-of the filter specifications, it's discarded.
+Lines beginning with a ``-'' (minus sign) are entries marked as being excluded
+from any following inclusions, which are marked with a ``+'' (plus sign).
.Pp
-Again, note that the NIS
-.Ql \&+
-and
-.Ql \&-
-entries themselves are handled in the order in which they were specified
-in the
-.Pa /etc/master.passwd
-file, since doing otherwise would lead to unpredictable behavior.
+If the second character of the line is a ``@'' (at sign), the operation
+involves the user fields of all entries in the netgroup specified by the
+remaining characters of the
+.Ar name
+field.
+Otherwise, the remainder of the
+.Ar name
+field is assumed to be a specific user name.
.Pp
-The end result is that
-.Tn FreeBSD Ns 's
-provides a very close approximation
-of
-.Tn SunOS Ns 's
-behavior while maintaining the database paradigm, though the
-.Xr getpwent 3
-functions do behave somewhat differently from their
-.Tn SunOS
-counterparts.
-The primary differences are:
-.Bl -bullet -offset indent
-.It
-Each NIS password map record can be mapped into the password
-local password space only once.
-.It
-The placement of the NIS
-.Ql \&+
+The ``+'' token may also be alone in the
+.Ar name
+field, which causes all users from either the Hesiod domain
+.Nm
+(with
+.Sq passwd_compat: dns )
+or
+.Sq passwd.byname
and
-.Ql \&-
-entries does not necessarily
-affect where NIS password records will be mapped into
-the password space.
-.El
-.Pp
-In 99% of all
-.Tn FreeBSD
-configurations, NIS client behavior will be
-indistinguishable from that of
-.Tn SunOS
-or other similar systems.
-Even
-so, users should be aware of these architectural differences.
+.Sq passwd.byuid
+.Tn NIS
+maps (with
+.Sq passwd_compat: nis )
+to be included.
.Pp
-.Ss Using groups instead of netgroups for NIS overrides
-.Tn FreeBSD
-offers the capability to do override matching based on
-user groups rather than netgroups.
-If, for example, an NIS entry
-is specified as:
-.Bd -literal -offset indent
-+@operator:::::::::
-
-.Ed
-the system will first try to match users against a netgroup called
-.Ql operator .
-If an
-.Ql operator
-netgroup doesn't exist, the system
-will try to match users against the normal
-.Ql operator
-group instead.
-.Ss Changes in behavior from older versions of FreeBSD
-There have been several bug fixes and improvements in
-.Tn FreeBSD Ns 's
-NIS/YP handling, some of which have caused changes in behavior.
-While the behavior changes are generally positive, it is important
-that users and system administrators be aware of them:
-.Bl -enum -offset indent
-.It
-In versions prior to 2.0.5, reverse lookups (i.e. using
-.Fn getpwuid )
-would not have overrides applied, which is to say that it
-was possible for
-.Fn getpwuid
-to return a login name that
-.Fn getpwnam
-would not recognize.
-This has been fixed: overrides specified
-in
-.Pa /etc/master.passwd
-now apply to all
-.Xr getpwent 3
-functions.
-.It
-Prior to
-.Fx 2.0.5 ,
-netgroup overrides did not work at
-all, largely because
-.Tn FreeBSD
-did not have support for reading
-netgroups through NIS.
-Again, this has been fixed, and
-netgroups can be specified just as in
-.Tn SunOS
-and similar NIS-capable
-systems.
-.It
-.Tn FreeBSD
-now has NIS server capabilities and supports the use
-of
-.Pa master.passwd
-NIS maps in addition to the standard Sixth Edition format
-.Pa passwd
-maps.
-This means that you can specify change, expiration and class
-information through NIS, provided you use a
-.Tn FreeBSD
-system as
-the NIS server.
-.El
-.Sh FILES
-.Bl -tag -width /etc/master.passwd -compact
-.It Pa /etc/passwd
-.Tn ASCII
-password file, with passwords removed
-.It Pa /etc/pwd.db
-.Xr db 3 -format
-password database, with passwords removed
-.It Pa /etc/master.passwd
-.Tn ASCII
-password file, with passwords intact
-.It Pa /etc/spwd.db
-.Xr db 3 -format
-password database, with passwords intact
-.El
+If the entry contains non-empty
+.Ar uid
+or
+.Ar gid
+fields, the specified numbers will override the information retrieved
+from the Hesiod domain or the
+.Tn NIS
+maps. As well, if the
+.Ar gecos,
+.Ar dir
+or
+.Ar shell
+entries contain text, it will override the information included via
+Hesiod or
+.Tn NIS .
+On some systems, the
+.Ar passwd
+field may also be overridden.
.Sh SEE ALSO
.Xr chpass 1 ,
.Xr login 1 ,
.Xr passwd 1 ,
.Xr getpwent 3 ,
-.Xr login_getclass 3 ,
-.Xr yp 4 ,
-.Xr login.conf 5 ,
+.Xr netgroup 5 ,
.Xr adduser 8 ,
-.Xr pw 8 ,
.Xr pwd_mkdb 8 ,
-.Xr vipw 8
+.Xr vipw 8 ,
+.Xr yp 8
+.Pp
+.%T "Managing NFS and NIS"
+(O'Reilly & Associates)
.Sh BUGS
User information should (and eventually will) be stored elsewhere.
.Pp
-The YP/NIS password database makes encrypted passwords visible to
-ordinary users, thus making password cracking easier unless you use
-shadow passwords with the
-.Pa master.passwd
-maps and
-.Tn FreeBSD Ns 's
-.Xr ypserv 8
-server.
-.Pp
-Unless you're using
-.Tn FreeBSD Ns 's
-.Xr ypserv 8 ,
-which supports the use of
-.Pa master.passwd
-type maps,
-the YP/NIS password database will be in old-style (Sixth Edition) format,
-which means that site-wide values for user login class, password
-expiration date, and other fields present in the current format
-will not be available when a
-.Tn FreeBSD
-system is used as a client with
-a standard NIS server.
+Placing
+Sq compat
+exclusions in the file after any inclusions will have
+unexpected results.
.Sh COMPATIBILITY
The password file format has changed since
.Bx 4.3 .
@@ -776,10 +322,9 @@ The additional fields
and
.Dq expire
are added, but are turned off by default.
-These fields can then be set using
-.Xr vipw 8
-or
-.Xr pw 8 .
+Class is currently not implemented, but change and expire are; to set them,
+use the current day in seconds from the epoch + whatever number of seconds
+of offset you want.
.Bd -literal -offset indent
BEGIN { FS = ":"}
{ print $1 ":" $2 ":" $3 ":" $4 "::0:0:" $5 ":" $6 ":" $7 }
@@ -789,14 +334,15 @@ A
.Nm
file format appeared in
.At v6 .
-The YP/NIS functionality is modeled after
-.Tn SunOS
-and first appeared in
-.Fx 1.1
-The override capability is new in
-.Fx 2.0 .
-The override capability was updated to properly support netgroups
-in
-.Fx 2.0.5 .
-Support for comments first appeared in
-.Fx 3.0 .
+.Pp
+The
+.Tn NIS
+.Nm
+file format first appeared in SunOS.
+.Pp
+The Hesiod support first appeared in
+.Fx 4.1 .
+It was imported from the
+.Nx
+Project, where it first appeared in
+.Nx 1.4 .
diff --git a/share/man/man8/yp.8 b/share/man/man8/yp.8
index dda8944..3ceab06 100644
--- a/share/man/man8/yp.8
+++ b/share/man/man8/yp.8
@@ -57,14 +57,8 @@ daemon makes direct
library calls since there are no
functions in the standard C library for reading bootparams.
.Tn NIS
-support for the hosts, services and rpc databases is enabled by
-uncommenting the
-.Em nis
-line in
-.Pa /etc/host.conf .
-.Tn NIS
-support for the remaining services is
-activated by adding a special '+' entry to the appropriate file.
+support is enabled in
+.Xr nsswitch.conf .
.Pp
The
.Nm YP
diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile
index 7966608..8b2db0b 100644
--- a/usr.bin/chpass/Makefile
+++ b/usr.bin/chpass/Makefile
@@ -10,8 +10,9 @@ GENSRCS=yp.h yp_clnt.c yppasswd.h yppasswd_clnt.c yppasswd_private.h \
BINMODE=4555
.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw \
${.CURDIR}/../../libexec/ypxfr \
- ${.CURDIR}/../../usr.sbin/rpc.yppasswdd
-CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../usr.sbin/vipw
+ ${.CURDIR}/../../usr.sbin/rpc.yppasswdd \
+ ${.CURDIR}/../../lib/libc/gen
+CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../usr.sbin/vipw -I${.CURDIR}/../../lib/libc/gen
LINKS= ${BINDIR}/chpass ${BINDIR}/chfn
LINKS+= ${BINDIR}/chpass ${BINDIR}/chsh
LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchpass
diff --git a/usr.bin/chpass/chpass.c b/usr.bin/chpass/chpass.c
index 77f9f78..69e700f 100644
--- a/usr.bin/chpass/chpass.c
+++ b/usr.bin/chpass/chpass.c
@@ -204,7 +204,7 @@ main(argc, argv)
if (uid)
baduser();
pw = &lpw;
- if (!pw_scan(arg, pw))
+ if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
exit(1);
}
username = pw->pw_name;
diff --git a/usr.bin/chpass/edit.c b/usr.bin/chpass/edit.c
index 6311d575..a5d3d5d 100644
--- a/usr.bin/chpass/edit.c
+++ b/usr.bin/chpass/edit.c
@@ -264,5 +264,5 @@ bad: (void)fclose(fp);
return (0);
}
free(p);
- return (pw_scan(buf, pw));
+ return (__pw_scan(buf, pw, _PWSCAN_WARN|_PWSCAN_MASTER));
}
diff --git a/usr.bin/hesinfo/Makefile b/usr.bin/hesinfo/Makefile
new file mode 100644
index 0000000..870db28
--- /dev/null
+++ b/usr.bin/hesinfo/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+PROG= hesinfo
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/hesinfo/hesinfo.1 b/usr.bin/hesinfo/hesinfo.1
new file mode 100644
index 0000000..b43910c
--- /dev/null
+++ b/usr.bin/hesinfo/hesinfo.1
@@ -0,0 +1,226 @@
+.\" $NetBSD: hesinfo.1,v 1.1 1999/01/25 22:45:55 lukem Exp $
+.\" $FreeBSD$
+.\"
+.\" from: #Id: hesinfo.1,v 1.9 1996/11/07 01:57:12 ghudson Exp #
+.\"
+.\" Copyright 1987, 1996 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.TH HESINFO 1 "27 October 1996"
+.FM mit
+.SH NAME
+hesinfo \- find out what is stored in the Hesiod database
+.SH SYNOPSIS
+.nf
+hesinfo \fI[-bl]\fR \fIHesiodName\fR \fIHesiodNameType\fR
+.SH DESCRIPTION
+.I hesinfo
+takes two arguments, a name to be resolved and a string, known
+as a HesiodNameType. It then prints the information returned by
+the Hesiod nameserver.
+.PP
+The value returned by
+.B hesinfo
+is of the type
+.I HesiodNameType.
+.PP
+.I hesinfo
+understands the following options:
+.TP
+.B -l
+Selects long format.
+.TP
+.B -b
+Prints the fully-qualified string passed to the nameserver.
+
+.PP
+.SS VALID Hesiod_Names
+The following types of identifiers may be used in the
+.I HesiodName
+argument to
+.B hesinfo.
+These values will be resolved by accessing the
+.B hesiod
+database.
+
+.TP
+.B \<username>
+the 8-character-or-less string used to identify users or classes
+(e.g. joeuser, root, 1.00, etc).
+Used with the
+.I Hesiod_Name_Types
+.BR passwd,
+.BR pobox,
+and
+.BR filsys.
+
+
+.TP
+.B \<uid>
+the id number assigned to a user.
+
+.TP
+.B \<groupid>
+the id number assigned to a group.
+
+.TP
+.B \<groupname>
+a name identifying a unique group.
+
+.TP
+.B \<file-system-name>
+the name of an athena file system.
+
+.TP
+.B \<rvd server>:<pack>
+the name of an rvd's server and pack seperated by a colon.
+
+.TP
+.B \<nfs server>:<partition>
+the name of an nfs server and its partition seperated by a colon.
+
+.TP
+.B \<workstation-name>
+the machine name of an Athena workstation (e.g. E40-343-3).
+
+.TP
+.B \<service-name>
+name of an Athena service (e.g. Zephyr).
+
+.TP
+.B \<service-type>
+name of Unix service (valid entries are defined in /etc/services).
+
+.TP
+.B \<printer-name>
+name of a printer.
+
+.TP
+.B \<printer-cluster-name>
+name of an Athena print cluster.
+
+.TP
+.B \<foo>
+some
+.B hesinfo
+calls (e.g.
+.B prclusterlist
+) do not require a specific
+.I HesiodName
+argument. However, you must include a dummy string (e.g. 'foo') for
+.B hesinfo
+ to work properly.
+
+
+
+
+.PP
+.SS VALID Hesiod_Name_Types
+The following symbols are valid substitutions for the
+.I HesiodNameType
+argument to
+.B hesinfo.
+
+.TP
+.B \ passwd
+returns string suitable for inclusion in
+.I /etc/passwd,
+searching with
+.B <username>.
+
+.TP
+.B \ pobox
+returns information on the pobox assigned to the user specified by
+.I HesiodName,
+searching with
+.B <username>.
+
+
+.TP
+.B \ uid
+returns string suitable for inclusion in
+.I /etc/passwd,
+searching with
+.B <uid>.
+
+.TP
+.B \ gid
+returns string suitable for inclusion in
+.I /etc/group,
+searching with
+.B <groupid>.
+
+.TP
+.B \ group
+returns string suitable for inclusion in
+.I /etc/group,
+searching with
+.B <groupname>.
+
+.TP
+.B \ grplist
+returns subgroups included in superset
+defined by
+.B <groupname>.
+
+.TP
+.B \ filsys
+returns file system type, export point, server, mount mode, and import point
+for the following valid
+.I HesiodNames
+(see above)
+.B - <file system name>, <username>, <rvd server>:<pack>,
+.B and <nfs server>:<partition>
+
+.TP
+.B \ cluster
+returns information about the local cluster the workstation, specified by
+.B <workstation name>.
+Included is information about the local file and print servers. This
+information is accesses by
+.B clusterinfo
+at boot time.
+
+.TP
+.B \ sloc
+returns network name of service host for
+.B <service-name>.
+
+.TP
+.B \ service
+returns Internet protocol type and protocol service port for
+.B <service-type>.
+
+.TP
+.B \ pcap
+returns a valid entry for /etc/printcap for
+.B <printer-name>.
+
+.TP
+.B \ prcluserlist
+returns a list of print clusters.
+
+.TP
+.B \ prcluster
+returns a list of printers in a cluster specified by
+.B <printer-cluster-name>.
+
+.SH FILES
+/etc/hesiod.conf
+.SH "SEE ALSO"
+`Hesiod - Project Athena Technical Plan -- Name Service', named(8), hesiod(3)
+.SH AUTHOR
+Steve Dyer, IBM/Project Athena
+.br
+Copyright 1987, 1988, 1996 by the Massachusetts Institute of Technology.
+.br
diff --git a/usr.bin/hesinfo/hesinfo.c b/usr.bin/hesinfo/hesinfo.c
new file mode 100644
index 0000000..d0d9c2d
--- /dev/null
+++ b/usr.bin/hesinfo/hesinfo.c
@@ -0,0 +1,116 @@
+/* $NetBSD: hesinfo.c,v 1.1 1999/01/25 22:45:55 lukem Exp $ */
+
+/* Copyright 1988, 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is a simple driver for the Hesiod library. */
+
+
+#include <sys/cdefs.h>
+#ifndef lint
+static char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <err.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main __P((int, char **));
+extern char *__progname;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char **list, **p, *bindname, *name, *type;
+ int lflag = 0, errflg = 0, bflag = 0, c;
+ void *context;
+
+ while ((c = getopt(argc, argv, "lb")) != -1) {
+ switch (c) {
+ case 'l':
+ lflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ default:
+ errflg++;
+ break;
+ }
+ }
+ if (argc - optind != 2 || errflg) {
+ fprintf(stderr, "Usage: %s [-bl] name type\n", __progname);
+ fprintf(stderr, "\t-l selects long format\n");
+ fprintf(stderr, "\t-b also does hes_to_bind conversion\n");
+ exit(2);
+ }
+ name = argv[optind];
+ type = argv[optind + 1];
+
+ if (hesiod_init(&context) < 0) {
+ if (errno == ENOEXEC)
+ warnx(
+ "hesiod_init: Invalid Hesiod configuration file.");
+ else
+ warn("hesiod_init");
+ }
+ /* Display bind name if requested. */
+ if (bflag) {
+ if (lflag)
+ printf("hes_to_bind(%s, %s) expands to\n", name, type);
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname) {
+ if (lflag)
+ printf("nothing\n");
+ if (errno == ENOENT)
+ warnx("hesiod_to_bind: Unknown rhs-extension.");
+ else
+ warn("hesiod_to_bind");
+ exit(1);
+ }
+ printf("%s\n", bindname);
+ free(bindname);
+ if (lflag)
+ printf("which ");
+ }
+ if (lflag)
+ printf("resolves to\n");
+
+ /* Do the hesiod resolve and check for errors. */
+ list = hesiod_resolve(context, name, type);
+ if (!list) {
+ if (lflag)
+ printf("nothing\n");
+ if (errno == ENOENT)
+ warnx("hesiod_resolve: Hesiod name not found.");
+ else
+ warn("hesiod_resolve");
+ exit(1);
+ }
+ /* Display the results. */
+ for (p = list; *p; p++)
+ printf("%s\n", *p);
+
+ hesiod_free_list(context, list);
+ hesiod_end(context);
+ exit(0);
+}
diff --git a/usr.sbin/pwd_mkdb/Makefile b/usr.sbin/pwd_mkdb/Makefile
index 86116fec..057ac6b 100644
--- a/usr.sbin/pwd_mkdb/Makefile
+++ b/usr.sbin/pwd_mkdb/Makefile
@@ -1,5 +1,9 @@
+# $FreeBSD$
# @(#)Makefile 8.1 (Berkeley) 6/6/93
+.PATH: ${.CURDIR}/../../lib/libc/gen # for pw_scan.c
+CFLAGS+= -I${.CURDIR}/../../lib/libc/gen # for pw_scan.h
+
PROG= pwd_mkdb
SRCS= pw_scan.c pwd_mkdb.c
MAN8= pwd_mkdb.8
diff --git a/usr.sbin/pwd_mkdb/pw_scan.c b/usr.sbin/pwd_mkdb/pw_scan.c
deleted file mode 100644
index d0fb5f1..0000000
--- a/usr.sbin/pwd_mkdb/pw_scan.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * 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 University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 lint
-#if 0
-static char sccsid[] = "@(#)pw_scan.c 8.3 (Berkeley) 4/2/94";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-/*
- * This module is used to "verify" password entries by chpass(1) and
- * pwd_mkdb(8).
- */
-
-#include <sys/param.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "pw_scan.h"
-
-/*
- * Some software assumes that IDs are short. We should emit warnings
- * for id's which can not be stored in a short, but we are more liberal
- * by default, warning for IDs greater than USHRT_MAX.
- *
- * If pw_big_ids_warning is anything other than -1 on entry to pw_scan()
- * it will be set based on the existance of PW_SCAN_BIG_IDS in the
- * environment.
- */
-int pw_big_ids_warning = -1;
-
-int
-pw_scan(bp, pw)
- char *bp;
- struct passwd *pw;
-{
- uid_t id;
- int root;
- char *p, *sh;
-
- if (pw_big_ids_warning == -1)
- pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0;
-
- pw->pw_fields = 0;
- if (!(pw->pw_name = strsep(&bp, ":"))) /* login */
- goto fmt;
- root = !strcmp(pw->pw_name, "root");
- if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0'))
- pw->pw_fields |= _PWF_NAME;
-
- if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */
- goto fmt;
- if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD;
-
- if (!(p = strsep(&bp, ":"))) /* uid */
- goto fmt;
- if (p[0])
- pw->pw_fields |= _PWF_UID;
- else {
- if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
- warnx("no uid for user %s", pw->pw_name);
- return (0);
- }
- }
- id = strtoul(p, (char **)NULL, 10);
- if (errno == ERANGE) {
- warnx("%s > max uid value (%u)", p, ULONG_MAX);
- return (0);
- }
- if (root && id) {
- warnx("root uid should be 0");
- return (0);
- }
- if (pw_big_ids_warning && id > USHRT_MAX) {
- warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
- /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
- }
- pw->pw_uid = id;
-
- if (!(p = strsep(&bp, ":"))) /* gid */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_GID;
- id = strtoul(p, (char **)NULL, 10);
- if (errno == ERANGE) {
- warnx("%s > max gid value (%u)", p, ULONG_MAX);
- return (0);
- }
- if (pw_big_ids_warning && id > USHRT_MAX) {
- warnx("%s > recommended max gid value (%u)", p, USHRT_MAX);
- /* return (0); This should not be fatal! */
- }
- pw->pw_gid = id;
-
- pw->pw_class = strsep(&bp, ":"); /* class */
- if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
-
- if (!(p = strsep(&bp, ":"))) /* change */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_CHANGE;
- pw->pw_change = atol(p);
-
- if (!(p = strsep(&bp, ":"))) /* expire */
- goto fmt;
- if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
- pw->pw_expire = atol(p);
-
- if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */
- goto fmt;
- if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS;
-
- if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */
- goto fmt;
- if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR;
-
- if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */
- goto fmt;
-
- p = pw->pw_shell;
- if (root && *p) /* empty == /bin/sh */
- for (setusershell();;) {
- if (!(sh = getusershell())) {
- warnx("warning, unknown root shell");
- break;
- }
- if (!strcmp(p, sh))
- break;
- }
- if(p[0]) pw->pw_fields |= _PWF_SHELL;
-
- if ((p = strsep(&bp, ":"))) { /* too many */
-fmt: warnx("corrupted entry");
- return (0);
- }
- return (1);
-}
diff --git a/usr.sbin/pwd_mkdb/pw_scan.h b/usr.sbin/pwd_mkdb/pw_scan.h
deleted file mode 100644
index 2519bd4..0000000
--- a/usr.sbin/pwd_mkdb/pw_scan.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*-
- * Copyright (c) 1994
- * The Regents of the University of California. All rights reserved.
- *
- * 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 University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- * @(#)pw_scan.h 8.1 (Berkeley) 4/1/94
- *
- * $FreeBSD$
- */
-
-extern int pw_big_ids_warning;
-
-extern int pw_scan __P((char *, struct passwd *));
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c
index 9d77b27..01e52de 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.c
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -520,7 +520,7 @@ scan(fp, pw)
} else
is_comment = 0;
- if (!pw_scan(line, pw)) {
+ if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) {
warnx("at line #%d", lcnt);
fmt: errno = EFTYPE; /* XXX */
error(pname);
diff --git a/usr.sbin/rarpd/rarpd.8 b/usr.sbin/rarpd/rarpd.8
index 465a16f..93bae8b 100644
--- a/usr.sbin/rarpd/rarpd.8
+++ b/usr.sbin/rarpd/rarpd.8
@@ -111,7 +111,7 @@ If this name is not in the DNS but is in
the DNS lookup
can cause a delayed RARP response, so in this situation it is reccommended to
configure
-.Pa /etc/host.conf
+.Xr nsswitch.conf
to read
.Pa /etc/hosts
first.
diff --git a/usr.sbin/sysinstall/installUpgrade.c b/usr.sbin/sysinstall/installUpgrade.c
index 1c70020..f82bfb7 100644
--- a/usr.sbin/sysinstall/installUpgrade.c
+++ b/usr.sbin/sysinstall/installUpgrade.c
@@ -78,7 +78,6 @@ static HitList etc_files [] = {
{ JUST_COPY, "gettytab", TRUE, NULL },
{ JUST_COPY, "gnats", TRUE, NULL },
{ JUST_COPY, "group", FALSE, NULL },
- { JUST_COPY, "host.conf", TRUE, NULL },
{ JUST_COPY, "hosts", TRUE, NULL },
{ JUST_COPY, "hosts.equiv", TRUE, NULL },
{ JUST_COPY, "hosts.lpd", TRUE, NULL },
@@ -96,6 +95,7 @@ static HitList etc_files [] = {
{ JUST_COPY, "namedb", TRUE, NULL },
{ JUST_COPY, "networks", TRUE, NULL },
{ JUST_COPY, "newsyslog.conf", TRUE, NULL },
+ { JUST_COPY, "nsswitch.conf", TRUE, NULL },
{ JUST_COPY, "pam.conf", TRUE, NULL },
{ JUST_COPY, "passwd", TRUE, NULL },
{ JUST_COPY, "periodic", TRUE, NULL },
diff --git a/usr.sbin/ypserv/ypserv.8 b/usr.sbin/ypserv/ypserv.8
index a5807ed..763e944 100644
--- a/usr.sbin/ypserv/ypserv.8
+++ b/usr.sbin/ypserv/ypserv.8
@@ -435,8 +435,8 @@ within the filesystem.
the
.Tn NIS
maps
-.It Pa /etc/host.conf
-resolver configuration file
+.It Pa /etc/nsswitch.conf
+name switch configuration file
.It Pa /var/yp/securenets
host access control file
.El
OpenPOWER on IntegriCloud