summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ypcmd
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/ypcmd
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/ypcmd')
-rw-r--r--usr/src/cmd/ypcmd/Makefile305
-rw-r--r--usr/src/cmd/ypcmd/client.xml103
-rw-r--r--usr/src/cmd/ypcmd/getlist.c150
-rw-r--r--usr/src/cmd/ypcmd/makedbm.c592
-rw-r--r--usr/src/cmd/ypcmd/mkalias.c358
-rw-r--r--usr/src/cmd/ypcmd/mknetid/Makefile61
-rw-r--r--usr/src/cmd/ypcmd/mknetid/getname.c127
-rw-r--r--usr/src/cmd/ypcmd/mknetid/mknetid.c556
-rw-r--r--usr/src/cmd/ypcmd/multi.awk.sh127
-rw-r--r--usr/src/cmd/ypcmd/multi.sh86
-rw-r--r--usr/src/cmd/ypcmd/net_files/Makefile515
-rw-r--r--usr/src/cmd/ypcmd/net_files/aliases29
-rw-r--r--usr/src/cmd/ypcmd/net_files/netid28
-rw-r--r--usr/src/cmd/ypcmd/net_files/nicknames10
-rw-r--r--usr/src/cmd/ypcmd/net_files/publickey36
-rw-r--r--usr/src/cmd/ypcmd/net_files/updaters42
-rw-r--r--usr/src/cmd/ypcmd/nick.c112
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/Makefile59
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/getgroup.c249
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/getgroup.h50
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/revnetgroup.c299
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/table.c100
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/table.h58
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/util.c112
-rw-r--r--usr/src/cmd/ypcmd/revnetgroup/util.h67
-rw-r--r--usr/src/cmd/ypcmd/rpc_bootstrap.c484
-rw-r--r--usr/src/cmd/ypcmd/server.xml95
-rw-r--r--usr/src/cmd/ypcmd/shared/ancil.c91
-rw-r--r--usr/src/cmd/ypcmd/shared/lockmap.c359
-rw-r--r--usr/src/cmd/ypcmd/shared/utils.c344
-rw-r--r--usr/src/cmd/ypcmd/stdethers.c77
-rw-r--r--usr/src/cmd/ypcmd/stdhosts.c335
-rw-r--r--usr/src/cmd/ypcmd/udpublickey.c188
-rw-r--r--usr/src/cmd/ypcmd/xfr.xml87
-rw-r--r--usr/src/cmd/ypcmd/yp.sh116
-rw-r--r--usr/src/cmd/ypcmd/yp2lscripts/Makefile63
-rw-r--r--usr/src/cmd/ypcmd/yp2lscripts/inityp2l.sh5784
-rw-r--r--usr/src/cmd/ypcmd/yp2lscripts/ypmap2src.sh971
-rw-r--r--usr/src/cmd/ypcmd/yp_b.h192
-rw-r--r--usr/src/cmd/ypcmd/yp_b_subr.c1511
-rw-r--r--usr/src/cmd/ypcmd/yp_b_svc.c680
-rw-r--r--usr/src/cmd/ypcmd/yp_getalias.c203
-rw-r--r--usr/src/cmd/ypcmd/ypalias.c146
-rw-r--r--usr/src/cmd/ypcmd/ypcat.c324
-rw-r--r--usr/src/cmd/ypcmd/ypdefs.h104
-rw-r--r--usr/src/cmd/ypcmd/ypinit.sh515
-rw-r--r--usr/src/cmd/ypcmd/ypmatch.c299
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/Makefile119
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/changepasswd.c766
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/passwd.xml87
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/yplckpwdf.c95
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/yppasswdd.c661
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/yppasswdd.dfl34
-rw-r--r--usr/src/cmd/ypcmd/yppasswd/yppasswdxdr.c72
-rw-r--r--usr/src/cmd/ypcmd/yppoll.c384
-rw-r--r--usr/src/cmd/ypcmd/yppush.c1102
-rw-r--r--usr/src/cmd/ypcmd/ypserv.c643
-rw-r--r--usr/src/cmd/ypcmd/ypserv_ancil.c184
-rw-r--r--usr/src/cmd/ypcmd/ypserv_map.c263
-rw-r--r--usr/src/cmd/ypcmd/ypserv_net_secure.c230
-rw-r--r--usr/src/cmd/ypcmd/ypserv_proc.c1521
-rw-r--r--usr/src/cmd/ypcmd/ypserv_resolv.c431
-rw-r--r--usr/src/cmd/ypcmd/ypserv_resolv_common.c90
-rw-r--r--usr/src/cmd/ypcmd/ypserv_resolv_common.h106
-rw-r--r--usr/src/cmd/ypcmd/ypset.c319
-rw-r--r--usr/src/cmd/ypcmd/ypstart.sh108
-rw-r--r--usr/src/cmd/ypcmd/ypstop.sh40
-rw-r--r--usr/src/cmd/ypcmd/ypsym.h180
-rw-r--r--usr/src/cmd/ypcmd/ypupdated.c411
-rw-r--r--usr/src/cmd/ypcmd/ypupdated/Makefile99
-rw-r--r--usr/src/cmd/ypcmd/ypupdated/openchild.c152
-rw-r--r--usr/src/cmd/ypcmd/ypupdated/rpc.ypupdated.c388
-rw-r--r--usr/src/cmd/ypcmd/ypupdated/update.xml87
-rw-r--r--usr/src/cmd/ypcmd/ypupdated/ypupdate_prot.x62
-rw-r--r--usr/src/cmd/ypcmd/ypv1_prot.h145
-rw-r--r--usr/src/cmd/ypcmd/ypv1_xdr.c109
-rw-r--r--usr/src/cmd/ypcmd/ypv2_bind.h88
-rw-r--r--usr/src/cmd/ypcmd/ypwhich.c774
-rw-r--r--usr/src/cmd/ypcmd/ypxfr.c1885
-rw-r--r--usr/src/cmd/ypcmd/ypxfr_1perday.sh41
-rw-r--r--usr/src/cmd/ypcmd/ypxfr_1perhour.sh35
-rw-r--r--usr/src/cmd/ypcmd/ypxfr_2perday.sh41
-rw-r--r--usr/src/cmd/ypcmd/ypxfrd.x100
-rw-r--r--usr/src/cmd/ypcmd/ypxfrd_client.c301
-rw-r--r--usr/src/cmd/ypcmd/ypxfrd_server.c438
-rw-r--r--usr/src/cmd/ypcmd/ypxfrd_svc.c273
86 files changed, 30063 insertions, 0 deletions
diff --git a/usr/src/cmd/ypcmd/Makefile b/usr/src/cmd/ypcmd/Makefile
new file mode 100644
index 0000000000..938c65b7fa
--- /dev/null
+++ b/usr/src/cmd/ypcmd/Makefile
@@ -0,0 +1,305 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+BINPROG = ypmatch ypwhich ypcat
+SBINPROG = makedbm ypalias ypinit yppoll ypset
+NETYPPROG = ypbind ypxfr yppush udpublickey mkalias \
+ multi multi.awk stdethers stdhosts \
+ ypxfr_1perday ypxfr_1perhour ypxfr_2perday \
+ ypstart ypstop
+NIS2LDAPPROG = ypxfrd ypserv
+METHOD = yp
+PROG= $(BINPROG) $(SBINPROG) $(NETYPPROG) $(NIS2LDAPPROG) $(METHOD)
+
+MANIFEST = server.xml client.xml xfr.xml
+
+include ../Makefile.cmd
+
+ROOTMANIFESTDIR = $(ROOTSVCNETWORKNIS)
+ROOTMETHOD = $(ROOTLIBSVCMETHOD)/$(METHOD)
+
+# installed directories
+NETSVC = $(ROOTLIB)/netsvc
+NETYP = $(NETSVC)/yp
+
+ROOTVAR_YP = $(ROOT)/var/yp
+ROOTBINDING = $(ROOTVAR_YP)/binding
+ROOTDIRS = $(ROOT) $(ROOTUSR) $(ROOTLIB) $(ROOTETC) $(ROOTVAR) \
+ $(NETSVC) $(NETYP) $(ROOTVAR_YP) $(ROOTBINDING) \
+ $(ROOTUSRSBIN) $(ROOTBIN)
+
+$(BINPROG) := LDLIBS += -lnsl
+$(NETYPPROG) := LDLIBS += -lnsl
+$(NIS2LDAPPROG) := LDLIBS += -lc -lnsl -lnisdb
+ypinit := LDLIBS += -lnsl
+yppoll := LDLIBS += -lnsl
+ypset := LDLIBS += -lnsl
+
+$(ROOTVAR_YP)/aliases := GROUP=bin
+$(ROOTVAR_YP)/aliases := FILEMODE=555
+$(ROOTMANIFEST) := FILEMODE = 0444
+
+YPFILES = Makefile aliases nicknames updaters
+ETCFILES = publickey
+ROOTYPFILES= $(YPFILES:%=$(ROOTVAR_YP)/%)
+ROOTETCFILE= $(ETCFILES:%=$(ROOTETC)/%)
+
+TXTS= $(ETCFILES:%=net_files/%) $(YPFILES:%=net_files/%)
+SUBDIRS = yppasswd mknetid revnetgroup ypupdated yp2lscripts
+
+YPBINDOBJ= yp_b_svc.o yp_b_subr.o rpc_bootstrap.o getlist.o
+#
+# Some sort of obsolete idea of common files which are only now used by a
+# few minor utilities
+#
+COMMONOBJ= getlist.o yp_getalias.o
+
+#
+# Objects shared between all the major components
+#
+SHARED_DIR= ./shared
+SHAREDOBJ= $(SHARED_DIR)/utils.o $(SHARED_DIR)/lockmap.o $(SHARED_DIR)/ancil.o
+SHARESRC = $(SHAREOBJ:.o=.c)
+
+YPXFROBJ = ypxfr.o ypxfrd_client.o ypxfrd_xdr.o
+YPMATOBJ = ypmatch.o nick.o
+YPWHIOBJ = ypwhich.o nick.o
+YPCATOBJ = ypcat.o nick.o
+UDPUBLICKEYOBJ = udpublickey.o
+MKALIASOBJ = mkalias.o
+STDETHERSOBJ = stdethers.o
+STDHOSTSOBJ = stdhosts.o
+#COMMONCLNTOBJ = clnt_create_rsvd.o
+YPSERVOBJ = ypserv.o ypserv_map.o \
+ ypserv_proc.o ypserv_ancil.o \
+ ypserv_resolv.o ypserv_resolv_common.o \
+ ypv1_xdr.o ypserv_net_secure.o
+YPPUSHOBJ = yppush.o
+YPXFRDOBJ = ypxfrd_svc.o ypxfrd_xdr.o ypxfrd_server.o \
+ ypserv_net_secure.o
+
+NETYPOBJ = $(YPXFROBJ) $(YPXFRDOBJ) $(YPSERVOBJ) $(YPPUSHOBJ) \
+ $(YPBINDOBJ) $(UDPUBLICKEYOBJ)
+OBJS = $(NETYPOBJ) $(MKALIASOBJ) $(COMMONOBJ) $(SHAREDOBJ) \
+ $(YPPUSHOBJ) $(YPMATOBJ) $(YPWHIOBJ) $(YPCATOBJ) \
+ $(STDETHERSOBJ) $(STDHOSTSOBJ) makedbm.o ypalias.o pong.o
+
+BINSRC = $(BINPROG:=.c)
+
+SBINSRC = $(SBINPROG:=.c)
+
+NETYPSRC = $(NETYPOBJ:.o=.c)
+
+YPBINDSRC = $(YPBINSOBJ:.o=.c)
+
+YPXFRSRC = $(YPXFROBJ:.o=.c)
+
+YPSERVSRC = $(YPSERVOBJ:.o=.c)
+
+YPPUSHSRC = $(YPPUSHOBJ:.o=.c)
+
+YPXFRDSRC = $(YPXFRDOBJ:.o=.c)
+
+YPMASTERSRC = $(YPMASTEROBJ:.o=.c)
+
+YPALLSRC = $(YPALLOBJ:.o=.c)
+
+COMMONSRC = $(COMMONOBJ:.o=.c)
+
+#COMMONCLNTSRC = $(COMMONCLNTOBJ:.o=.c)
+
+SRCS = $(BINSRC) $(SBINSRC) $(NETYPSRC) \
+ $(COMMONSRC) $(SHAREDSRC)
+
+CLEANFILES = ypxfrd.h ypxfrd_xdr.c
+
+IBINPROG= $(BINPROG:%=$(ROOTBIN)/%)
+ISBINPROG= $(SBINPROG:%=$(ROOTUSRSBIN)/%)
+INETYPPROG= $(NETYPPROG:%=$(NETYP)/%)
+INIS2LDAPPROG = $(NIS2LDAPPROG:%=$(NETYP)/%)
+
+NIS2LDAPINC = -I$(SRC)/lib/libnisdb/yptol
+
+#conditional assignments
+ypalias.o := CPPFLAGS= -DMAIN $(CPPFLAGS.master)
+makedbm.o := CPPFLAGS= $(CPPFLAGS.master)
+yp_b_svc.o := CPPFLAGS += -DINIT_DEFAULT
+ypxfrd_svc.o := CPPFLAGS += -Dmain=_main
+ypxfr.o := CPPFLAGS += $(NIS2LDAPINC)
+yppush.o := CPPFLAGS += $(NIS2LDAPINC)
+$(NIS2LDAPPROG) := CPPFLAGS += $(NIS2LDAPINC)
+$(SHAREDOBJ) := CPPFLAGS += -I$(SRC)/lib/libnisdb/yptol
+$(IBINPROG) := GROUP= other
+$(ROOTVAR_YP)/Makefile := FILEMODE= 555
+$(ROOTVAR_YP)/nicknames := FILEMODE= 644
+$(ROOTVAR_YP)/updaters := FILEMODE= 500
+$(ROOTETC)/publickey := FILEMODE= 644
+# non-default file attributes to avoid conflict with rpcsrc
+$(NETSVC) := GROUP= sys
+NETYP = $(NETSVC)/yp
+$(NETYP) := GROUP=bin
+
+
+all:= TARGET= all
+install:= TARGET= install
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+lint:= TARGET= lint
+cstyle := TARGET= cstyle
+
+all: $(SHAREDOBJ) $(SUBDIRS) $(PROG) $(TXTS)
+
+# install rules
+$(ROOTVAR_YP)/% \
+$(ROOTETC)/%: net_files/%
+ $(INS.file)
+
+$(ROOTVAR_YP)/% : net_files/%
+ $(INS.file)
+
+$(NETYP)/%: %
+ $(INS.file)
+
+.KEEP_STATE:
+
+$(SHAREDOBJ): $(SHAREDSRC)
+ $(COMPILE.c) $(SHAREDSRC) -o $@ $<
+
+ypbind: $(YPBINDOBJ)
+ $(LINK.c) $(YPBINDOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+makedbm ypalias: $$@.o $(COMMONOBJ)
+ $(LINK.c) -o $@ $@.o $(COMMONOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+ypmatch: $(YPMATOBJ)
+ $(LINK.c) -o $@ $(YPMATOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+ypwhich: $(YPWHIOBJ)
+ $(LINK.c) -o $@ $(YPWHIOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+ypcat: $(YPCATOBJ)
+ $(LINK.c) -o $@ $(YPCATOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+ypxfrd_xdr.c: ypxfrd.x
+ $(RM) ypxfrd_xdr.c; $(RPCGEN) -C -c ypxfrd.x -o ypxfrd_xdr.c
+
+ypxfrd.h: ypxfrd.x
+ $(RM) ypxfrd.h; $(RPCGEN) -C -h ypxfrd.x -o ypxfrd.h
+
+ypxfrd_xdr.o ypxfrd_client.o: ypxfrd.h
+
+#clnt_create_rsvd.o ypxfr.o: clnt_create_rsvd.h
+
+ypxfrd: $(YPXFRDOBJ) $(SHAREDOBJ)
+ $(LINK.cc) $(YPXFRDOBJ) $(SHAREDOBJ) \
+ -o $@ $(LDLIBS) -lc
+ $(POST_PROCESS)
+
+ypxfr: $(YPXFROBJ) $(COMMONOBJ) $(YPMASTEROBJ) $(SHAREDOBJ)
+ $(LINK.c) -o $@ $(YPXFROBJ) $(YPMASTEROBJ) $(COMMONOBJ) \
+ $(SHAREDOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+ypserv: $(YPSERVOBJ) $(COMMONOBJ) $(SHAREDOBJ)
+ $(LINK.cc) $(YPSERVOBJ) $(COMMONOBJ) \
+ $(SHAREDOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+yppush: $(YPPUSHOBJ) $(COMMONOBJ)
+ $(LINK.c) $(YPPUSHOBJ) $(COMMONOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+udpublickey: $(UDPUBLICKEYOBJ)
+ $(LINK.c) $(UDPUBLICKEYOBJ) -o $@
+ $(POST_PROCESS)
+
+mkalias: $(MKALIASOBJ)
+ $(LINK.c) $(MKALIASOBJ) -o $@ -lnsl
+ $(POST_PROCESS)
+
+stdethers: $(STDETHERSOBJ)
+ $(LINK.c) $(STDETHERSOBJ) -o $@ -lsocket
+ $(POST_PROCESS)
+
+stdhosts: $(STDHOSTSOBJ)
+ $(LINK.c) $(STDHOSTSOBJ) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(PROG) $(ROOTDIRS) $(ROOTETCFILE) $(ROOTYPFILES) $(IBINPROG) \
+ $(ISBINPROG) $(INETYPPROG) $(INIS2LDAPPROG) $(SUBDIRS) $(ROOTMANIFEST) \
+ $(ROOTMETHOD)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+lint := CPPFLAGS += -I$(SRC)/lib/libnisdb/yptol
+
+lint: $(SUBDIRS)
+ $(LINT.c) ypmatch.c nick.c -lnsl
+ $(LINT.c) ypwhich.c nick.c -lnsl
+ $(LINT.c) ypcat.c nick.c -lnsl
+ $(LINT.c) makedbm.c getlist.c yp_getalias.c
+ $(LINT.c) ypalias.c getlist.c yp_getalias.c
+ $(LINT.c) yp_b_svc.c yp_b_subr.c rpc_bootstrap.c getlist.c -lnsl
+ $(LINT.c) ypxfr.c ypxfrd_client.c ypxfrd_xdr.c getlist.c yp_getalias.c \
+ ./shared/utils.c ./shared/lockmap.c ./shared/ancil.c -lnsl
+ $(LINT.c) yppush.c getlist.c yp_getalias.c -lnsl
+ $(LINT.c) udpublickey.c
+ $(LINT.c) mkalias.c -lnsl
+ $(LINT.c) stdethers.c -lsocket
+ $(LINT.c) stdhosts.c -lnsl
+ $(LINT.c) ypxfrd_svc.c ypxfrd_xdr.c ypxfrd_server.c \
+ ypserv_net_secure.c \
+ ./shared/utils.c ./shared/lockmap.c ./shared/ancil.c \
+ -lnsl -lnisdb
+ $(LINT.c) ypserv.c ypserv_map.c ypserv_proc.c ypserv_ancil.c \
+ ypserv_resolv.c ypserv_resolv_common.c ypv1_xdr.c \
+ ypserv_net_secure.c getlist.c yp_getalias.c \
+ ./shared/utils.c ./shared/lockmap.c ./shared/ancil.c \
+ -lnsl -lnisdb
+
+check: $(CHKMANIFEST)
+
+cstyle: $(SUBDIRS)
+ ${CSTYLE} `echo $(SRCS) | sed 's/ypinit.c//'`
+
+clean: $(SUBDIRS)
+ $(RM) $(OBJS) $(CLEANFILES)
+
+clobber: clean $(SUBDIRS)
+ $(RM) $(PROG)
+
+FRC:
diff --git a/usr/src/cmd/ypcmd/client.xml b/usr/src/cmd/ypcmd/client.xml
new file mode 100644
index 0000000000..23a4fa3f21
--- /dev/null
+++ b/usr/src/cmd/ypcmd/client.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWnisr:ypclient'>
+
+<service
+ name='network/nis/client'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <dependency
+ name='fs'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='rpcbind'
+ grouping='require_all'
+ restart_on='restart'
+ type='service'>
+ <service_fmri value='svc:/network/rpc/bind' />
+ </dependency>
+
+ <dependency
+ name='domain'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/identity:domain' />
+ </dependency>
+
+ <dependency
+ name='yp_server'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/network/nis/server' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/yp'
+ timeout_seconds='300' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ NIS (YP) client
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='ypstart' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/ypcmd/getlist.c b/usr/src/cmd/ypcmd/getlist.c
new file mode 100644
index 0000000000..45467e290f
--- /dev/null
+++ b/usr/src/cmd/ypcmd/getlist.c
@@ -0,0 +1,150 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1992 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ypsym.h"
+
+extern void free();
+extern char *strdup();
+
+/*
+ * Add a name to the list
+ */
+static listofnames *
+newname(str)
+char *str;
+{
+ listofnames *it;
+ char *copy;
+
+ if (str == NULL)
+ return (NULL);
+ copy = strdup(str);
+ if (copy == NULL)
+ return (NULL);
+ it = (listofnames *) malloc(sizeof (listofnames));
+ if (it == NULL) {
+ free(copy);
+ return (NULL);
+ }
+ it->name = copy;
+ it->nextname = NULL;
+ return (it);
+}
+
+/*
+ * Assemble the list of names
+ */
+listofnames *
+names(filename)
+char *filename;
+{
+ listofnames *nameslist;
+ listofnames *end;
+ listofnames *nname;
+ FILE *fyle;
+ char line[256];
+ char name[256];
+
+ fyle = fopen(filename, "r");
+ if (fyle == NULL) {
+ return (NULL);
+ }
+ nameslist = NULL;
+ while (fgets(line, sizeof (line), fyle)) {
+ if (line[0] == '#') continue;
+ if (line[0] == '\0') continue;
+ if (line[0] == '\n') continue;
+ nname = newname(line);
+ if (nname) {
+ if (nameslist == NULL) {
+ nameslist = nname;
+ end = nname;
+ } else {
+ end->nextname = nname;
+ end = nname;
+ }
+ } else
+ fprintf(stderr,
+ "file %s bad malloc %s\n", filename, name);
+ }
+ fclose(fyle);
+ return (nameslist);
+}
+
+void
+free_listofnames(locallist)
+listofnames *locallist;
+{
+ listofnames *next = (listofnames *)NULL;
+
+ for (; locallist; locallist = next) {
+ next = locallist->nextname;
+ if (locallist->name)
+ free(locallist->name);
+ free((char *)locallist);
+ }
+}
+
+
+#ifdef MAIN
+main(argc, argv)
+char **argv;
+{
+ listofnames *list;
+ list = names(argv[1]);
+#ifdef DEBUG
+ print_listofnames(list);
+#endif
+ free_listofnames(list);
+#ifdef DEBUG
+ printf("Done\n");
+#endif
+}
+#endif
+
+#ifdef DEBUG
+void
+print_listofnames(list)
+listofnames *list;
+{
+ if (list == NULL)
+ printf("NULL\n");
+ for (; list; list = list->nextname)
+ printf("%s\n", list->name);
+}
+#endif
diff --git a/usr/src/cmd/ypcmd/makedbm.c b/usr/src/cmd/ypcmd/makedbm.c
new file mode 100644
index 0000000000..72e113af7f
--- /dev/null
+++ b/usr/src/cmd/ypcmd/makedbm.c
@@ -0,0 +1,592 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#undef NULL
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/systeminfo.h>
+#include <dlfcn.h>
+
+#include "ypdefs.h"
+#include "ypsym.h"
+USE_YP_MASTER_NAME
+USE_YP_LAST_MODIFIED
+USE_YP_INPUT_FILE
+USE_YP_OUTPUT_NAME
+USE_YP_DOMAIN_NAME
+USE_YP_SECURE
+USE_YP_INTERDOMAIN
+USE_DBM
+
+#ifdef SYSVCONFIG
+extern void sysvconfig();
+#endif
+extern int yp_getalias();
+
+#define MAXLINE 4096 /* max length of input line */
+#define DEFAULT_SEP " "
+static char *get_date();
+static char *any();
+static void addpair();
+static void unmake();
+static void usage();
+
+int inode_dev_valid = 0;
+ino_t inode;
+dev_t dev;
+
+/*
+ * Interpose _close(2) to enable us to keep one of the output
+ * files open until process exit.
+ */
+int
+_close(int filedes) {
+
+ struct stat sb;
+ static int (*fptr)() = 0;
+
+ if (fptr == 0) {
+ fptr = (int (*)())dlsym(RTLD_NEXT, "_close");
+ if (fptr == 0) {
+ fprintf(stderr, "makedbm: dlopen(_close): %s\n",
+ dlerror());
+ errno = ELIBACC;
+ return (-1);
+ }
+ }
+
+ if (inode_dev_valid != 0 && fstat(filedes, &sb) == 0) {
+ if (sb.st_ino == inode && sb.st_dev == dev) {
+ /* Keep open; pretend successful */
+ return (0);
+ }
+ }
+
+ return ((*fptr)(filedes));
+}
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *infp, *outfp;
+ datum key, content, tmp;
+ char buf[MAXLINE];
+ char pagbuf[MAXPATHLEN];
+ char tmppagbuf[MAXPATHLEN];
+ char dirbuf[MAXPATHLEN];
+ char tmpdirbuf[MAXPATHLEN];
+ char *p, ic;
+ char *infile, *outfile;
+ char outalias[MAXPATHLEN];
+ char outaliasmap[MAXNAMLEN];
+ char outaliasdomain[MAXNAMLEN];
+ char *last_slash, *next_to_last_slash;
+ char *infilename, *outfilename, *mastername, *domainname,
+ *interdomain_bind, *security, *lower_case_keys;
+ char *key_sep = DEFAULT_SEP;
+ char local_host[MAX_MASTER_NAME];
+ int cnt, i;
+ DBM *fdb;
+ struct stat statbuf;
+ int num_del_to_match = 0;
+ /* flag to indicate if matching char can be escaped */
+ int count_esp = 0;
+
+ /* Ignore existing umask, always force 077 (owner rw only) */
+ umask(077);
+
+ infile = outfile = NULL; /* where to get files */
+ /* name to imbed in database */
+ infilename = outfilename = mastername = domainname = interdomain_bind =
+ security = lower_case_keys = NULL;
+ argv++;
+ argc--;
+ while (argc > 0) {
+ if (argv[0][0] == '-' && argv[0][1]) {
+ switch (argv[0][1]) {
+ case 'i':
+ infilename = argv[1];
+ argv++;
+ argc--;
+ break;
+ case 'o':
+ outfilename = argv[1];
+ argv++;
+ argc--;
+ break;
+ case 'm':
+ mastername = argv[1];
+ argv++;
+ argc--;
+ break;
+ case 'b':
+ interdomain_bind = argv[0];
+ break;
+ case 'd':
+ domainname = argv[1];
+ argv++;
+ argc--;
+ break;
+ case 'l':
+ lower_case_keys = argv[0];
+ break;
+ case 's':
+ security = argv[0];
+ break;
+ case 'S' :
+ strcpy(key_sep, argv[1]);
+ argv++;
+ argc--;
+ if (strlen(key_sep) != 1) {
+ fprintf(stderr,
+ "bad separator\n");
+ usage();
+ }
+ break;
+ case 'D' :
+ num_del_to_match = atoi(argv[1]);
+ argv++;
+ argc--;
+ break;
+ case 'E' :
+ count_esp = 1;
+ break;
+ case 'u':
+ unmake(argv[1]);
+ argv++;
+ argc--;
+ exit(0);
+ default:
+ usage();
+ }
+ } else if (infile == NULL)
+ infile = argv[0];
+ else if (outfile == NULL)
+ outfile = argv[0];
+ else
+ usage();
+ argv++;
+ argc--;
+ }
+ if (infile == NULL || outfile == NULL)
+ usage();
+
+ /*
+ * do alias mapping if necessary
+ */
+ last_slash = strrchr(outfile, '/');
+ if (last_slash) {
+ *last_slash = '\0';
+ next_to_last_slash = strrchr(outfile, '/');
+ if (next_to_last_slash) *next_to_last_slash = '\0';
+ } else next_to_last_slash = NULL;
+
+#ifdef DEBUG
+ if (last_slash) printf("last_slash=%s\n", last_slash+1);
+ if (next_to_last_slash) printf("next_to_last_slash=%s\n",
+ next_to_last_slash+1);
+#endif /* DEBUG */
+
+ /* reads in alias file for system v filename translation */
+#ifdef SYSVCONFIG
+ sysvconfig();
+#endif
+
+ if (last_slash && next_to_last_slash) {
+ if (yp_getalias(last_slash+1, outaliasmap, MAXALIASLEN) < 0) {
+ if ((int)strlen(last_slash+1) <= MAXALIASLEN)
+ strcpy(outaliasmap, last_slash+1);
+ else
+ fprintf(stderr,
+ "makedbm: warning: no alias for %s\n",
+ last_slash+1);
+ }
+#ifdef DEBUG
+ printf("%s\n", last_slash+1);
+ printf("%s\n", outaliasmap);
+#endif /* DEBUG */
+ if (yp_getalias(next_to_last_slash+1, outaliasdomain,
+ NAME_MAX) < 0) {
+ if ((int)strlen(last_slash+1) <= NAME_MAX)
+ strcpy(outaliasdomain, next_to_last_slash+1);
+ else
+ fprintf(stderr,
+ "makedbm: warning: no alias for %s\n",
+ next_to_last_slash+1);
+ }
+#ifdef DEBUG
+ printf("%s\n", next_to_last_slash+1);
+ printf("%s\n", outaliasdomain);
+#endif /* DEBUG */
+ sprintf(outalias, "%s/%s/%s", outfile, outaliasdomain,
+ outaliasmap);
+#ifdef DEBUG
+ printf("outlias=%s\n", outalias);
+#endif /* DEBUG */
+
+ } else if (last_slash) {
+ if (yp_getalias(last_slash+1, outaliasmap, MAXALIASLEN) < 0) {
+ if ((int)strlen(last_slash+1) <= MAXALIASLEN)
+ strcpy(outaliasmap, last_slash+1);
+ else
+ fprintf(stderr,
+ "makedbm: warning: no alias for %s\n",
+ last_slash+1);
+ }
+ if (yp_getalias(outfile, outaliasdomain, NAME_MAX) < 0) {
+ if ((int)strlen(outfile) <= NAME_MAX)
+ strcpy(outaliasdomain, outfile);
+ else
+ fprintf(stderr,
+ "makedbm: warning: no alias for %s\n",
+ last_slash+1);
+ }
+ sprintf(outalias, "%s/%s", outaliasdomain, outaliasmap);
+ } else {
+ if (yp_getalias(outfile, outalias, MAXALIASLEN) < 0) {
+ if ((int)strlen(last_slash+1) <= MAXALIASLEN)
+ strcpy(outalias, outfile);
+ else
+ fprintf(stderr,
+ "makedbm: warning: no alias for %s\n",
+ outfile);
+ }
+ }
+#ifdef DEBUG
+ fprintf(stderr, "outalias=%s\n", outalias);
+ fprintf(stderr, "outfile=%s\n", outfile);
+#endif /* DEBUG */
+
+ strcpy(tmppagbuf, outalias);
+ strcat(tmppagbuf, ".tmp");
+ strcpy(tmpdirbuf, tmppagbuf);
+ strcat(tmpdirbuf, dbm_dir);
+ strcat(tmppagbuf, dbm_pag);
+
+ /* Loop until we can lock the tmpdirbuf file */
+ for (;;) {
+
+ if (strcmp(infile, "-") != 0)
+ infp = fopen(infile, "r");
+ else if (fstat(fileno(stdin), &statbuf) == -1) {
+ fprintf(stderr, "makedbm: can't open stdin\n");
+ exit(1);
+ } else
+ infp = stdin;
+
+ if (infp == NULL) {
+ fprintf(stderr, "makedbm: can't open %s\n", infile);
+ exit(1);
+ }
+
+ if ((outfp = fopen(tmpdirbuf, "w")) == (FILE *)NULL) {
+ fprintf(stderr, "makedbm: can't create %s\n",
+ tmpdirbuf);
+ exit(1);
+ }
+
+ if (lockf(fileno(outfp), F_TLOCK, 0) == 0) {
+ /* Got exclusive access; save inode and dev */
+ if (fstat(fileno(outfp), &statbuf) != 0) {
+ fprintf(stderr, "makedbm: can't fstat ");
+ perror(tmpdirbuf);
+ exit(1);
+ }
+ inode = statbuf.st_ino;
+ dev = statbuf.st_dev;
+ inode_dev_valid = 1;
+ break;
+ }
+
+ if (errno != EAGAIN) {
+ fprintf(stderr, "makedbm: can't lock ");
+ perror(tmpdirbuf);
+ exit(1);
+ }
+
+ /*
+ * Someone else is holding the lock.
+ * Close both output and input file
+ * (the latter to ensure consistency
+ * if the input file is updated while
+ * we're suspended), wait a little,
+ * and try again.
+ */
+ if (infp != stdin)
+ (void) fclose(infp);
+ (void) fclose(outfp);
+ sleep(1);
+ }
+
+ if (fopen(tmppagbuf, "w") == (FILE *)NULL) {
+ fprintf(stderr, "makedbm: can't create %s\n", tmppagbuf);
+ exit(1);
+ }
+ strcpy(dirbuf, outalias);
+ strcat(dirbuf, ".tmp");
+ if ((fdb = dbm_open(dirbuf, O_RDWR | O_CREAT, 0644)) == NULL) {
+ fprintf(stderr, "makedbm: can't open %s\n", dirbuf);
+ exit(1);
+ }
+ strcpy(dirbuf, outalias);
+ strcpy(pagbuf, outalias);
+ strcat(dirbuf, dbm_dir);
+ strcat(pagbuf, dbm_pag);
+ while (fgets(buf, sizeof (buf), infp) != NULL) {
+ p = buf;
+ cnt = strlen(buf) - 1; /* erase trailing newline */
+ while (p[cnt-1] == '\\') {
+ p += cnt-1;
+ if (fgets(p, sizeof (buf)-(p-buf), infp) == NULL)
+ goto breakout;
+ cnt = strlen(p) - 1;
+ }
+ if (strcmp(key_sep, DEFAULT_SEP) == 0) {
+ p = any(buf, " \t\n", num_del_to_match, count_esp);
+ } else {
+ p = any(buf, key_sep, num_del_to_match, count_esp);
+ }
+ key.dptr = buf;
+ key.dsize = p - buf;
+ for (;;) {
+ if (p == NULL || *p == NULL) {
+ fprintf(stderr,
+ "makedbm: source files is garbage!\n");
+ exit(1);
+ }
+ if (*p != ' ' && *p != '\t' && *p != key_sep[0])
+ break;
+ p++;
+ }
+ content.dptr = p;
+ content.dsize = strlen(p) - 1; /* erase trailing newline */
+ if (lower_case_keys) {
+ for (i = (strncmp(key.dptr, "YP_MULTI_", 9) ? 0 : 9);
+ i < key.dsize; i++) {
+
+ ic = *(key.dptr+i);
+ if (isascii(ic) && isupper(ic))
+ *(key.dptr+i) = tolower(ic);
+ }
+ }
+ tmp = dbm_fetch(fdb, key);
+ if (tmp.dptr == NULL) {
+ if (dbm_store(fdb, key, content, 1) != 0) {
+ printf("problem storing %.*s %.*s\n",
+ key.dsize, key.dptr,
+ content.dsize, content.dptr);
+ exit(1);
+ }
+ }
+#ifdef DEBUG
+ else {
+ printf("duplicate: %.*s %.*s\n",
+ key.dsize, key.dptr,
+ content.dsize, content.dptr);
+ }
+#endif
+ }
+ breakout:
+ addpair(fdb, yp_last_modified, get_date(infile));
+ if (infilename)
+ addpair(fdb, yp_input_file, infilename);
+ if (outfilename)
+ addpair(fdb, yp_output_file, outfilename);
+ if (domainname)
+ addpair(fdb, yp_domain_name, domainname);
+ if (security)
+ addpair(fdb, yp_secure, "");
+ if (interdomain_bind)
+ addpair(fdb, yp_interdomain, "");
+ if (!mastername) {
+ sysinfo(SI_HOSTNAME, local_host, sizeof (local_host) - 1);
+ mastername = local_host;
+ }
+ addpair(fdb, yp_master_name, mastername);
+ (void) dbm_close(fdb);
+#ifdef DEBUG
+ fprintf(stderr, ".tmp ndbm map closed. ndbm successful !\n");
+#endif
+ if (rename(tmppagbuf, pagbuf) < 0) {
+ perror("makedbm: rename");
+ unlink(tmppagbuf); /* Remove the tmp files */
+ unlink(tmpdirbuf);
+ exit(1);
+ }
+ if (rename(tmpdirbuf, dirbuf) < 0) {
+ perror("makedbm: rename");
+ unlink(tmppagbuf); /* Remove the tmp files */
+ unlink(tmpdirbuf);
+ exit(1);
+ }
+/*
+ * sprintf(buf, "mv %s %s", tmppagbuf, pagbuf);
+ * if (system(buf) < 0)
+ * perror("makedbm: rename");
+ * sprintf(buf, "mv %s %s", tmpdirbuf, dirbuf);
+ * if (system(buf) < 0)
+ * perror("makedbm: rename");
+ */
+ exit(0);
+}
+
+
+/*
+ * scans cp, looking for a match with any character
+ * in match. Returns pointer to place in cp that matched
+ * (or NULL if no match)
+ *
+ * It will find the num_del_to_match+1
+ * matching character in the line.
+ *
+ * The backslash escapes a delimiter if count_esp==1
+ * We don't count it as a character match if
+ * an escape character precedes a matching character.
+ *
+ */
+static char *
+any(cp, match, num_del_to_match, count_esp)
+ register char *cp;
+ char *match;
+ int num_del_to_match;
+ int count_esp;
+{
+ register char *mp, c, prev_char;
+ int num_del_matched;
+
+ num_del_matched = 0;
+ prev_char = ' ';
+ while (c = *cp) {
+ for (mp = match; *mp; mp++) {
+ if (*mp == c) {
+ if (!count_esp) {
+ num_del_matched++;
+ } else if (prev_char != '\\') {
+ num_del_matched++;
+ }
+ if (num_del_matched > num_del_to_match)
+ return (cp);
+ }
+ }
+ prev_char = c;
+ cp++;
+ }
+ return ((char *)0);
+}
+
+static char *
+get_date(name)
+ char *name;
+{
+ struct stat filestat;
+ static char ans[MAX_ASCII_ORDER_NUMBER_LENGTH];
+ /* ASCII numeric string */
+
+ if (strcmp(name, "-") == 0)
+ sprintf(ans, "%010ld", (long)time(0));
+ else {
+ if (stat(name, &filestat) < 0) {
+ fprintf(stderr, "makedbm: can't stat %s\n", name);
+ exit(1);
+ }
+ sprintf(ans, "%010ld", (long)filestat.st_mtime);
+ }
+ return (ans);
+}
+
+void
+usage()
+{
+ fprintf(stderr,
+"usage: makedbm -u file\n makedbm [-b] [-l] [-s] [-i YP_INPUT_FILE] "
+ "[-o YP_OUTPUT_FILE] [-d YP_DOMAIN_NAME] [-m YP_MASTER_NAME] "
+ "[-S DELIMITER] [-D NUM_DELIMITER_TO_SKIP] [-E] "
+ "infile outfile\n");
+ exit(1);
+}
+
+void
+addpair(fdb, str1, str2)
+DBM *fdb;
+char *str1, *str2;
+{
+ datum key;
+ datum content;
+
+ key.dptr = str1;
+ key.dsize = strlen(str1);
+ content.dptr = str2;
+ content.dsize = strlen(str2);
+ if (dbm_store(fdb, key, content, 1) != 0) {
+ printf("makedbm: problem storing %.*s %.*s\n",
+ key.dsize, key.dptr, content.dsize, content.dptr);
+ exit(1);
+ }
+}
+
+void
+unmake(file)
+ char *file;
+{
+ datum key, content;
+ DBM *fdb;
+
+ if (file == NULL)
+ usage();
+
+ if ((fdb = dbm_open(file, O_RDONLY, 0644)) == NULL) {
+ fprintf(stderr, "makedbm: couldn't open %s dbm file\n", file);
+ exit(1);
+ }
+
+ for (key = dbm_firstkey(fdb); key.dptr != NULL;
+ key = dbm_nextkey(fdb)) {
+ content = dbm_fetch(fdb, key);
+ printf("%.*s %.*s\n", key.dsize, key.dptr,
+ content.dsize, content.dptr);
+ }
+
+ dbm_close(fdb);
+}
diff --git a/usr/src/cmd/ypcmd/mkalias.c b/usr/src/cmd/ypcmd/mkalias.c
new file mode 100644
index 0000000000..015132005d
--- /dev/null
+++ b/usr/src/cmd/ypcmd/mkalias.c
@@ -0,0 +1,358 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*
+ * mkmap - program to convert the mail.aliases map into an
+ * inverse map of <user@host> back to <preferred-alias>
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ndbm.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <sys/systeminfo.h>
+
+#include "ypdefs.h"
+USE_YP_PREFIX
+USE_YP_MASTER_NAME
+USE_YP_LAST_MODIFIED
+
+#define MKAL_INCLUDE ":include:"
+
+void CopyName(char *dst, char *src, int len);
+int HostCheck(char *h, char *a);
+void DoName(char *cp);
+void UpperCase(char *cp);
+void AddYPEntries(void);
+
+int Verbose = 0; /* to get the gory details */
+int UucpOK = 0; /* pass all UUCP names right through */
+int DomainOK = 0; /* pass all Domain names (with dots) */
+int ErrorCheck = 0; /* check carefully for errors */
+int NoOutput = 0; /* no output, just do the check */
+int Simple = 0; /* Do not do the user name preference step */
+int NameMode = 0; /* Try to capitalize as names */
+
+DBM *Indbm=NULL, *Scandbm=NULL, *Outdbm=NULL;
+
+int
+IsMailingList(char *s)
+{
+ /*
+ * returns true if the given string is a mailing list
+ */
+ char *p;
+
+ if (strchr(s, ','))
+ return (1);
+ if (strchr(s, '|'))
+ return (1);
+ p = strchr(s, ':');
+ if (p && strncmp(p, MKAL_INCLUDE, sizeof (MKAL_INCLUDE)))
+ return (1);
+ return (0);
+}
+
+int
+IsQualified(char *s, char *p, char *h)
+{
+ /*
+ * returns true if the given string is qualified with a host name
+ */
+ register char *middle;
+
+ middle = strchr(s, '@');
+ if (middle) {
+ for (middle = s; *middle != '@'; *p++ = *middle++)
+ continue;
+ *p = '\0';
+ CopyName(h, middle+1, strlen(middle + 1));
+ return (1);
+ }
+ middle = strrchr(s, '!');
+ if (middle) {
+ strcpy(p, middle+1);
+ *middle = '\0';
+ CopyName(h, s, strlen(s));
+ *middle = '!';
+ return (1);
+ }
+ return (0);
+}
+
+int
+IsMaint(char *s)
+{
+ /*
+ * returns true if the given string is one of the maintenence
+ * strings used in sendmail or NIS.
+ */
+ if (*s == '@')
+ return (1);
+ if (strncmp(s, yp_prefix, yp_prefix_sz) == 0)
+ return (1);
+ return (0);
+}
+
+void
+CopyName(char *dst, char *src, int len)
+{
+ /*
+ * copy a string, but ignore white space
+ */
+ while (*src && len--) {
+ if (isspace(*src))
+ src++;
+ else
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+}
+
+int
+Compare(char *s1, char *s2)
+{
+ /*
+ * compare strings, but ignore white space
+ */
+ while (*s1 != '\0' && isspace(*s1))
+ s1++;
+ while (*s2 != '\0' && isspace(*s2))
+ s2++;
+ return (strcmp(s1, s2));
+}
+
+void
+ProcessMap(void)
+{
+ datum key, value, part, partvalue;
+ char address[PBLKSIZ]; /* qualified version */
+ char user[PBLKSIZ]; /* unqualified version */
+ char userpart[PBLKSIZ]; /* unqualified part of qualified addr. */
+ char hostpart[PBLKSIZ]; /* rest of qualified addr. */
+
+ for (key = dbm_firstkey(Scandbm); key.dptr != NULL;
+ key = dbm_nextkey(Scandbm)) {
+ value = dbm_fetch(Indbm, key);
+ CopyName(address, value.dptr, value.dsize);
+ CopyName(user, key.dptr, key.dsize);
+ if (address == NULL) continue;
+ if (IsMailingList(address)) continue;
+ if (!IsQualified(address, userpart, hostpart)) continue;
+ if (IsMaint(user)) continue;
+ if (ErrorCheck && HostCheck(hostpart, address)) {
+ printf("Invalid host %s in %s:%s\n",
+ hostpart, user, address);
+ continue;
+ }
+ part.dptr = userpart;
+ part.dsize = strlen(userpart) + 1;
+ if (Simple)
+ partvalue.dptr = NULL;
+ else
+ partvalue = dbm_fetch(Indbm, part);
+ value.dptr = address;
+ value.dsize = strlen(address) + 1;
+ if (partvalue.dptr != NULL &&
+ Compare(partvalue.dptr, user) == 0) {
+
+ if (NameMode)
+ DoName(userpart);
+ if (!NoOutput)
+ dbm_store(Outdbm, value, part, DBM_REPLACE);
+ if (Verbose) printf("%s --> %s --> %s\n",
+ userpart, user, address);
+ } else {
+ if (NameMode)
+ DoName(user);
+ key.dptr = user;
+ key.dsize = strlen(user) + 1;
+ if (!NoOutput)
+ dbm_store(Outdbm, value, key, DBM_REPLACE);
+ if (Verbose)
+ printf("%s --> %s\n", user, address);
+ }
+ }
+}
+
+
+/*
+ * Returns true if this is an invalid host
+ */
+int
+HostCheck(char *h, char *a)
+{
+ struct hostent *hp;
+
+ if (DomainOK && strchr(a, '.'))
+ return (0);
+
+ if (UucpOK && strchr(a, '!'))
+ return (0);
+
+ hp = gethostbyname(h);
+ return (hp == NULL);
+}
+
+/*
+ * Apply some Heurisitcs to upper case-ify the name
+ * If it has a dot in it.
+ */
+void
+DoName(char *cp)
+{
+ if (strchr(cp, '.') == NULL)
+ return;
+
+ while (*cp) {
+ UpperCase(cp);
+ while (*cp && *cp != '-' && *cp != '.')
+ cp++;
+ if (*cp)
+ cp++; /* skip past punctuation */
+ }
+}
+
+/*
+ * upper cases one name - stops at a .
+ */
+void
+UpperCase(char *cp)
+{
+ register ch = cp[0];
+
+ if (isupper(ch))
+ ch = tolower(ch);
+
+ if (ch == 'f' && cp[1] == 'f')
+ return; /* handle ff */
+
+ if (ch == 'm' && cp[1] == 'c' && islower(cp[2]))
+ cp[2] = toupper(cp[2]);
+ if (islower(ch))
+ cp[0] = toupper(ch);
+}
+
+void
+AddYPEntries(void)
+{
+ datum key, value;
+ char last_modified[PBLKSIZ];
+ char host_name[PBLKSIZ];
+ time_t now;
+
+ /*
+ * Add the special NIS entries.
+ */
+ key.dptr = yp_last_modified;
+ key.dsize = yp_last_modified_sz;
+ time(&now);
+ sprintf(last_modified, "%10.10d", now);
+ value.dptr = last_modified;
+ value.dsize = strlen(value.dptr);
+ dbm_store(Outdbm, key, value, DBM_REPLACE);
+
+ key.dptr = yp_master_name;
+ key.dsize = yp_master_name_sz;
+ sysinfo(SI_HOSTNAME, host_name, sizeof (host_name));
+ value.dptr = host_name;
+ value.dsize = strlen(value.dptr);
+ dbm_store(Outdbm, key, value, DBM_REPLACE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ while (argc > 1 && argv[1][0] == '-') {
+ switch (argv[1][1]) {
+ case 'v':
+ Verbose = 1;
+ break;
+
+ case 'u':
+ UucpOK = 1;
+ break;
+
+ case 'd':
+ DomainOK = 1;
+ break;
+
+ case 'e':
+ ErrorCheck = 1;
+ break;
+
+ case 's':
+ Simple = 1;
+ break;
+
+ case 'n':
+ NameMode = 1;
+ break;
+
+ default:
+ printf("Unknown option %c\n", argv[1][1]);
+ break;
+ }
+ argc--; argv++;
+ }
+ if (argc < 2) {
+printf("Usage: mkalias [-e] [-v] [-u] [-d] [-s] [-n] <input> <output>\n");
+ exit(1);
+ }
+ Indbm = dbm_open(argv[1], O_RDONLY, 0);
+ if (Indbm == NULL) {
+ printf("Unable to open input database %s\n", argv[1]);
+ exit(1);
+ }
+ Scandbm = dbm_open(argv[1], O_RDONLY, 0);
+ if (Scandbm == NULL) {
+ printf("Unable to open input database %s\n", argv[1]);
+ exit(1);
+ }
+ if (argv[2] == NULL)
+ NoOutput = 1;
+ else {
+ Outdbm = dbm_open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if (Outdbm == NULL) {
+ printf("Unable to open output database %s\n", argv[2]);
+ exit(1);
+ }
+ }
+ ProcessMap();
+ dbm_close(Indbm);
+ dbm_close(Scandbm);
+ if (!NoOutput) {
+ AddYPEntries();
+ dbm_close(Outdbm);
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/ypcmd/mknetid/Makefile b/usr/src/cmd/ypcmd/mknetid/Makefile
new file mode 100644
index 0000000000..97453b068e
--- /dev/null
+++ b/usr/src/cmd/ypcmd/mknetid/Makefile
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1994, 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = mknetid
+
+include ../../Makefile.cmd
+
+LDLIBS += -lnsl
+
+OBJS = mknetid.o getname.o
+SRCS = $(OBJS:.o=.c)
+
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTUSRSBINPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+ ${LINT.c} ${SRCS}
+
+cstyle:
+ ${CSTYLE} ${SRCS}
+
+clobber: clean
+ $(RM) $(PROG)
+
+FRC:
diff --git a/usr/src/cmd/ypcmd/mknetid/getname.c b/usr/src/cmd/ypcmd/mknetid/getname.c
new file mode 100644
index 0000000000..a2adc50190
--- /dev/null
+++ b/usr/src/cmd/ypcmd/mknetid/getname.c
@@ -0,0 +1,127 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (C) 1986,1987,1988,1989,1990 Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.3 */
+
+#include <stdio.h>
+#include <string.h>
+
+#define iseol(c) (c == 0 || c == '\n' || strchr(com, c) != NULL)
+#define issep(c) (strchr(sep, c) != NULL)
+#define isignore(c) (strchr(ignore, c) != NULL)
+
+/*
+ * getline()
+ * Read a line from a file.
+ * What's returned is a cookie to be passed to getname
+ */
+char **
+getline(line, maxlinelen, f, lcount, com)
+ char *line;
+ int maxlinelen;
+ FILE *f;
+ int *lcount;
+ char *com;
+{
+ char *p;
+ static char *lp;
+ do {
+ if (! fgets(line, maxlinelen, f)) {
+ return (NULL);
+ }
+ (*lcount)++;
+ } while (iseol(line[0]));
+ p = line;
+ for (;;) {
+ while (*p) {
+ p++;
+ }
+ if (*--p == '\n' && *--p == '\\') {
+ if (! fgets(p, maxlinelen, f)) {
+ break;
+ }
+ (*lcount)++;
+ } else {
+ break;
+ }
+ }
+ lp = line;
+ return (&lp);
+}
+
+
+/*
+ * getname()
+ * Get the next entry from the line.
+ * You tell getname() which characters to ignore before storing them
+ * into name, and which characters separate entries in a line.
+ * The cookie is updated appropriately.
+ * return:
+ * 1: one entry parsed
+ * 0: partial entry parsed, ran out of space in name
+ * -1: no more entries in line
+ */
+getname(name, namelen, ignore, sep, linep, com)
+ char *name;
+ int namelen;
+ char *ignore;
+ char *sep;
+ char **linep;
+ char *com;
+{
+ register char c;
+ register char *lp;
+ register char *np;
+
+ lp = *linep;
+ do {
+ c = *lp++;
+ } while (isignore(c) && !iseol(c));
+ if (iseol(c)) {
+ *linep = lp - 1;
+ return (-1);
+ }
+ np = name;
+ while (! issep(c) && ! iseol(c) && np - name < namelen) {
+ *np++ = c;
+ c = *lp++;
+ }
+ lp--;
+ if (np - name < namelen) {
+ *np = 0;
+ if (iseol(c)) {
+ *lp = 0;
+ } else {
+ lp++; /* advance over separator */
+ }
+ } else {
+ *linep = lp;
+ return (0);
+ }
+ *linep = lp;
+ return (1);
+}
diff --git a/usr/src/cmd/ypcmd/mknetid/mknetid.c b/usr/src/cmd/ypcmd/mknetid/mknetid.c
new file mode 100644
index 0000000000..46fada3ff9
--- /dev/null
+++ b/usr/src/cmd/ypcmd/mknetid/mknetid.c
@@ -0,0 +1,556 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (C) 1990-2000, Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.5 */
+
+/*
+ * Network name to unix credential database generator.
+ * Uses /etc/passwd, /etc/group, /etc/hosts and /etc/netid to
+ * create the database.
+ *
+ * If some user appears in passwd, they get an entry like:
+ * sun.<uid>@<domainname> <uid>:<gid1>,<gid2>,...
+ * If some host appears in hosts, it gets an entry like:
+ * sun.<hostname>@<domainname> 0:<hostname>
+ *
+ * The file /etc/netid is used to add other domains (possibly non-unix)
+ * to the database.
+ */
+#include <stdio.h>
+#include <pwd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+
+
+#define MAXNAMELEN 256
+#define MAXLINELEN 1024
+#define MAXDOMAINLEN 32
+
+#define GRPTABSIZE 256 /* size of group table */
+#define PRNTABSIZE 4096 /* size of printed item table */
+
+#define NUMGIDS (NGROUPS_MAX + 1) /* group-access-list + gid */
+
+extern char **getline();
+extern char *malloc();
+extern char *strcpy();
+
+/*
+ * The group list
+ * Store username and groups to which he/she belongs
+ */
+struct group_list {
+ char *user;
+ int group_len;
+ int groups[NUMGIDS];
+ struct group_list *next;
+};
+
+/*
+ * General purpose list of strings
+ */
+struct string_list {
+ char *str;
+ struct string_list *next;
+};
+
+static FILE *openfile();
+static char *scanargs();
+static int atoi();
+
+static char *cmdname; /* name of this program */
+static int quietmode; /* quiet mode: don't print error messages */
+static char *curfile; /* name of file we are parsing */
+static int curline; /* current line parsed in this file */
+
+static struct group_list *groups[GRPTABSIZE]; /* group table */
+static struct string_list *printed[PRNTABSIZE]; /* printed item table */
+static char domain[MAXDOMAINLEN]; /* name of our domain */
+
+static char PASSWD[] = "/etc/passwd"; /* default passwd database */
+static char IDMAP[] = "/etc/idmap"; /* default net-id map database */
+static char GROUP[] = "/etc/group"; /* default group database */
+static char HOSTS[] = "/etc/hosts"; /* default hosts database */
+
+static char *pwdfile = PASSWD; /* password file to parse */
+static char *grpfile = GROUP; /* group file */
+static char *hostfile = HOSTS; /* hosts file */
+static char *mapfile = IDMAP; /* network id file */
+
+/*
+ * Various separaters
+ */
+static char WHITE[] = "\t ";
+static char COLON[] = ":";
+static char COMMA[] = ",";
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ FILE *pf, *mf, *gf, *hf;
+
+ cmdname = argv[0];
+ if (!parseargs(argc, argv)) {
+ (void) fprintf(stderr,
+ "usage: %s [-q] [-pghm filename]\n", cmdname);
+ exit(1);
+ }
+ (void) getdomainname(domain, sizeof (domain));
+
+ pf = openfile(pwdfile);
+ gf = openfile(grpfile);
+ hf = openfile(hostfile);
+ mf = fopen(mapfile, "r");
+
+
+ if (mf != NULL) {
+ domapfile(mapfile, mf);
+ }
+ dogrpfile(grpfile, gf);
+ dopwdfile(pwdfile, pf);
+ dohostfile(hostfile, hf);
+
+ exit(0);
+ /* NOTREACHED */
+}
+
+/*
+ * Parse the network id mapping file
+ */
+domapfile(mapfile, mf)
+ char *mapfile;
+ FILE *mf;
+{
+ char **lp;
+ char line[MAXLINELEN];
+ char name[MAXNAMELEN];
+ int uid, gid;
+
+ curfile = mapfile;
+ curline = 0;
+ while (lp = getline(line, sizeof (line), mf, &curline, "#")) {
+ check_getname(lp, name, WHITE, WHITE, "#");
+ if (wasprinted(name)) {
+ multdef(name);
+ continue;
+ }
+ put_s(name);
+ (void) putchar(' ');
+ check_getname(lp, name, WHITE, COLON, "#");
+ uid = Atoi(name);
+ put_d(uid);
+ (void) putchar(':');
+ if (uid == 0) {
+ check_getname(lp, name, WHITE, "\t\n ", "#");
+ put_s(name);
+ (void) putchar(' ');
+ } else {
+ check_getname(lp, name, WHITE, ",\n", "#");
+ gid = Atoi(name);
+ put_d(gid);
+ while (getname(name, sizeof (name), WHITE, ",\n", lp,
+ "#") >= 0) {
+ gid = Atoi(name);
+ (void) putchar(',');
+ put_d(gid);
+ }
+ }
+ (void) putchar('\n');
+ }
+}
+
+
+/*
+ * Parse the groups file
+ */
+dogrpfile(grpfile, gf)
+ char *grpfile;
+ FILE *gf;
+{
+ char **lp;
+ char line[MAXLINELEN];
+ char name[MAXNAMELEN];
+ int gid;
+
+ curfile = grpfile;
+ curline = 0;
+ while (lp = getline(line, sizeof (line), gf, &curline, "")) {
+ check_getname(lp, name, WHITE, COLON, "");
+ if (name[0] == '+') {
+ continue;
+ }
+ check_getname(lp, name, WHITE, COLON, ""); /* ignore passwd */
+ check_getname(lp, name, WHITE, COLON, "");
+ gid = Atoi(name);
+ while (getname(name, sizeof (name), WHITE, COMMA, lp,
+ "") >= 0) {
+ storegid(gid, name);
+ }
+ }
+}
+
+
+/*
+ * Parse the password file
+ */
+dopwdfile(pwdfile, pf)
+ char *pwdfile;
+ FILE *pf;
+{
+ char **lp;
+ char line[MAXLINELEN];
+ char name[MAXNAMELEN];
+ char user[MAXNAMELEN];
+ int uid, gid;
+
+ curfile = pwdfile;
+ curline = 0;
+
+ while (lp = getline(line, sizeof (line), pf, &curline, "")) {
+ check_getname(lp, user, WHITE, COLON, ""); /* username */
+ if (user[0] == '-' || user[0] == '+') {
+ continue; /* NIS entry */
+ }
+ check_getname(lp, name, WHITE, COLON, ""); /* ignore passwd */
+ check_getname(lp, name, WHITE, COLON, ""); /* but get uid */
+ uid = Atoi(name);
+ user2netname(name, uid, domain);
+ if (wasprinted(name)) {
+ multdef(name);
+ continue;
+ }
+ put_s(name);
+ (void) putchar(' ');
+ check_getname(lp, name, WHITE, COLON, "");
+ gid = Atoi(name);
+ put_d(uid);
+ (void) putchar(':');
+ printgroups(user, gid);
+ }
+}
+
+
+/*
+ * Parse the hosts file
+ */
+dohostfile(hostfile, hf)
+ char *hostfile;
+ FILE *hf;
+{
+ char **lp;
+ char line[MAXLINELEN];
+ char name[MAXNAMELEN];
+ char netname[MAXNETNAMELEN];
+
+ curfile = hostfile;
+ curline = 0;
+ while (lp = getline(line, sizeof (line), hf, &curline, "#")) {
+ check_getname(lp, name, WHITE, WHITE, "#");
+ if (getname(name, MAXNAMELEN, WHITE, WHITE, lp, "#") != 1) {
+ continue;
+ }
+ host2netname(netname, name, domain);
+ if (wasprinted(netname)) {
+ multdef(netname);
+ continue;
+ }
+ (void) printf("%s 0:%.*s\n", netname, sizeof (name), name);
+ }
+}
+
+/*
+ * Open a file, exit on failure
+ */
+static FILE *
+openfile(fname)
+ char *fname;
+{
+ FILE *f;
+
+ f = fopen(fname, "r");
+ if (f == NULL) {
+ (void) fprintf(stderr, "%s: can't open %s\n", cmdname, fname);
+ exit(1);
+ }
+ return (f);
+}
+
+/*
+ * Print syntax error message, then exit
+ */
+syntaxerror()
+{
+ (void) fprintf(stderr, "%s: syntax error in file \"%s\", line %d\n",
+ cmdname, curfile, curline);
+ exit(1);
+}
+
+
+/*
+ * an atoi() that prints a message and exits upong failure
+ */
+static int
+Atoi(str)
+ char *str;
+{
+ int res;
+
+ if (!sscanf(str, "%d", &res)) {
+ syntaxerror();
+ }
+ return (res);
+}
+
+
+/*
+ * Attempt to get a token from a file, print a message and exit upon failure
+ */
+check_getname(lp, name, skip, term, com)
+ char **lp;
+ char *name;
+ char *skip;
+ char *term;
+ char *com;
+{
+ if (getname(name, MAXNAMELEN, skip, term, lp, com) != 1) {
+ syntaxerror();
+ }
+}
+
+/*
+ * Something was defined more than once
+ */
+multdef(name)
+ char *name;
+{
+ if (!quietmode) {
+ (void) fprintf(stderr,
+ "%s: %s multiply defined, other definitions ignored\n",
+ cmdname, name);
+ }
+}
+
+static
+hash(str, size)
+ unsigned char *str;
+ int size;
+{
+ unsigned val;
+ int flip;
+
+ val = 0;
+ flip = 0;
+ while (*str) {
+ if (flip) {
+ val ^= (*str++ << 6);
+ } else {
+ val ^= *str++;
+ }
+ flip = !flip;
+ }
+ return (val % size);
+}
+
+
+/*
+ * Check if an item has been printed
+ * If not, store the item into the printed item table
+ */
+static
+wasprinted(name)
+ char *name;
+{
+ struct string_list *s;
+ int val;
+
+ val = hash((unsigned char *) name, PRNTABSIZE);
+ for (s = printed[val]; s != NULL && strcmp(s->str, name); s = s->next)
+ ;
+ if (s != NULL) {
+ return (1);
+ }
+ s = (struct string_list *)malloc(sizeof (struct string_list));
+ s->str = malloc((unsigned)strlen(name) + 1);
+ (void) strcpy(s->str, name);
+ s->next = printed[val];
+ printed[val] = s;
+ return (0);
+}
+
+/*
+ * Add gid to the list of a user's groups
+ */
+storegid(gid, user)
+ int gid;
+ char *user;
+{
+ struct group_list *g;
+ int i;
+ int val;
+
+ val = hash((unsigned char *) user, GRPTABSIZE);
+ for (g = groups[val]; g != NULL && strcmp(g->user, user); g = g->next)
+ ;
+ if (g == NULL) {
+ g = (struct group_list *)malloc(sizeof (struct group_list));
+ g->user = malloc((unsigned)strlen(user) + 1);
+ (void) strcpy(g->user, user);
+ g->group_len = 1;
+ g->groups[0] = gid;
+ g->next = groups[val];
+ groups[val] = g;
+ } else {
+ for (i = 0; i < g->group_len; i++) {
+ if (g->groups[i] == gid) {
+ return;
+ }
+ }
+ if (g->group_len >= NUMGIDS) {
+ (void) fprintf(stderr, "%s: %s's groups exceed %d\n",
+ cmdname, user, NGROUPS_MAX);
+ return;
+ }
+ g->groups[g->group_len++] = gid;
+ }
+}
+
+/*
+ * print out a user's groups
+ */
+printgroups(user, gid)
+ char *user;
+ int gid;
+{
+ struct group_list *g;
+ int i;
+ int val;
+
+ val = hash((unsigned char *) user, GRPTABSIZE);
+ for (g = groups[val]; g != NULL && strcmp(g->user, user); g = g->next)
+ ;
+ put_d(gid);
+ if (g != NULL) {
+ for (i = 0; i < g->group_len; i++) {
+ if (gid != g->groups[i]) {
+ (void) putchar(',');
+ put_d(g->groups[i]);
+ }
+ }
+ }
+ (void) putchar('\n');
+}
+
+
+/*
+ * Parse command line arguments
+ */
+parseargs(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ int j;
+ static struct {
+ char letter;
+ char *standard;
+ char **filename;
+ } whattodo[] = {
+ { 'p', PASSWD, &pwdfile },
+ { 'g', GROUP, &grpfile },
+ { 'm', IDMAP, &mapfile },
+ { 'h', HOSTS, &hostfile }
+ };
+
+#define TABSIZE sizeof (whattodo)/sizeof (whattodo[0])
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ if (argv[i][2] != 0) {
+ return (0);
+ }
+ if (argv[i][1] == 'q') {
+ quietmode = 1;
+ continue;
+ }
+ for (j = 0; j < TABSIZE; j++) {
+ if (whattodo[j].letter == argv[i][1]) {
+ if (*whattodo[j].filename !=
+ whattodo[j].standard) {
+ return (0);
+ }
+ if (++i == argc) {
+ return (0);
+ }
+ *whattodo[j].filename = argv[i];
+ break;
+ }
+ }
+ if (j == TABSIZE) {
+ return (0);
+ }
+ }
+ }
+ return (1);
+}
+
+/*
+ * Print a string, quickly
+ */
+put_s(s)
+ char *s;
+{
+ (void) fwrite(s, strlen(s), 1, stdout);
+}
+
+/*
+ * Print an integer, quickly
+ */
+put_d(d)
+ int d;
+{
+ char buf[20];
+ char *p;
+
+ if (d == 0) {
+ (void) putchar('0');
+ return;
+ }
+ if (d < 0) {
+ (void) putchar('-');
+ d = -d;
+ }
+ p = buf + sizeof (buf);
+ *--p = 0;
+ while (d > 0) {
+ *--p = (d % 10) + '0';
+ d /= 10;
+ }
+ put_s(p);
+}
diff --git a/usr/src/cmd/ypcmd/multi.awk.sh b/usr/src/cmd/ypcmd/multi.awk.sh
new file mode 100644
index 0000000000..068300f805
--- /dev/null
+++ b/usr/src/cmd/ypcmd/multi.awk.sh
@@ -0,0 +1,127 @@
+#!/usr/bin/nawk -f
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1996, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Awk code to handle the creation of the YP_MULTI_ entries
+# in the hosts.byname map. Called by multi directly.
+#
+
+{
+ # Here we loop through the list of hostnames
+ # doing two separate things...
+ # First, we're building a list of hostnames
+ # for the current IP address ($1).
+ # Second, if we've seen a name before then
+ # we add the current address ($1) to a list
+ # of address associated with this particular
+ # name ($i).
+ #
+ # Note, that we're pretty careful about keeping
+ # out duplicates (and this has a cost).
+
+ for (i = 2; i <= NF; i++) {
+ # Make the namelist for this address
+ if (namelist[$1] == "") {
+ namelist[$1] = $i;
+ } else if (namelist[$1] == $i) {
+ ;
+ } else if (index(namelist[$1], $i) == 0) {
+ namelist[$1] = namelist[$1] " " $i;
+ } else {
+ nf = 1;
+ numnames = split(namelist[$1], n);
+ for (j = 1; j <= numnames; j++) {
+ if (n[j] == $i) {
+ nf = 0;
+ break;
+ }
+ }
+ if (nf) {
+ namelist[$1] = namelist[$1] " " $i;
+ nf = 0;
+ }
+ }
+
+ # Do we have an address for this name?
+ # If not, and it's not already there, add it.
+ if (addr[$i] == "") {
+ addr[$i] = $1;
+ } else if (index(addr[$i], $1) == 0) {
+ addr[$i] = addr[$i] "," $1
+ }
+ }
+}
+
+END {
+ # There are now a bunch o addresses in the addr
+ # array that are actually lists. We go through
+ # all of them here and build a list of hostname
+ # aliases into the namelist array.
+ #
+ for (host in addr) {
+ if (index(addr[host], ",") == 0)
+ continue;
+ numaddr = split(addr[host], tmpaddr, ",");
+ for (i = 1; i <= numaddr; i++) {
+ numnames = split(namelist[tmpaddr[i]], tmpname);
+ for (j = 1; j <= numnames; j++) {
+ if (namelist[addr[host]] == "") {
+ namelist[addr[host]] = tmpname[j];
+ continue;
+ }
+ if (namelist[addr[host]] == tmpname[j]) {
+ continue;
+ }
+ if (index(namelist[addr[host]], tmpname[j]) == 0) {
+ namelist[addr[host]] = namelist[addr[host]] " " tmpname[j];
+ continue;
+ } else {
+ nf = 1;
+ for (k = 1; k <= numnames; k++) {
+ if (tmpname[j] == tmpname[k]) {
+ nf = 0;
+ break;
+ }
+ }
+ if (nf == 1) {
+ namelist[addr[host]] = namelist[addr[host]] " " tmpname[j];
+ nf = 1;
+ }
+ }
+ }
+ }
+ }
+
+ # Now do that funky output thang...
+ for (host in addr) {
+ if (index(addr[host], ",")) {
+ printf("YP_MULTI_");
+ }
+ printf("%s %s\t%s\n",
+ host, addr[host], namelist[addr[host]]);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/multi.sh b/usr/src/cmd/ypcmd/multi.sh
new file mode 100644
index 0000000000..9286bd6dec
--- /dev/null
+++ b/usr/src/cmd/ypcmd/multi.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1996, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Script to examine hosts file and make "magic" entries for
+# those hosts that have multiple IP addresses.
+#
+#
+
+MAKEDBM=/usr/sbin/makedbm
+STDHOSTS=/usr/lib/netsvc/yp/stdhosts
+MULTIAWK=/usr/lib/netsvc/yp/multi.awk
+MAP="hosts.byname"
+
+USAGE="Usage: multi [-b] [-l] [-s] [-n] [hosts file]
+Where:
+ -b Add YP_INTERDOMAIN flag to hosts map
+ -l Convert keys to lower case before creating map
+ -s Add YP_SECURE flag to hosts map
+ -n Add IPv6 and IPv4 host addresses to ipnodes map
+
+ hosts file defaults to /etc/hosts"
+
+while getopts blsn c
+do
+ case $c in
+ b) BFLAG=-b;;
+ l) LFLAG=-l;;
+ s) SFLAG=-s;;
+ n) NFLAG=-n;;
+ \?) echo "$USAGE"
+ exit 2;;
+ esac
+done
+
+if [ "$NFLAG" = "-n" ]
+then
+ MAP="ipnodes.byname"
+fi
+
+shift `expr $OPTIND - 1`
+
+if [ "$1" ]
+then
+ HOSTS=$1
+elif [ "$NFLAG" = "-n" ]
+then
+ HOSTS=/etc/inet/ipnodes
+else
+ HOSTS=/etc/hosts
+fi
+
+if [ "$HOSTS" = "-" ]
+then
+ unset HOSTS
+fi
+
+cd /var/yp/`domainname` && \
+ sed -e '/^[ ]*$/d' -e '/^#/d' -e 's/#.*$//' $HOSTS | \
+ $STDHOSTS $NFLAG | \
+ $MULTIAWK - | \
+ $MAKEDBM $BFLAG $LFLAG $SFLAG - $MAP
diff --git a/usr/src/cmd/ypcmd/net_files/Makefile b/usr/src/cmd/ypcmd/net_files/Makefile
new file mode 100644
index 0000000000..08d464d5c2
--- /dev/null
+++ b/usr/src/cmd/ypcmd/net_files/Makefile
@@ -0,0 +1,515 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+#
+# Portions of this source code were derived from Berkeley
+# under license from the Regents of the University of
+# California.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+#----
+# It is somewhat confusing to note that Solaris 2.x uses /etc/auto_master
+# instead of the 4.x /etc/auto.master file name because of NIS+ treating a
+# "." in a special way.
+#
+# Set the following variable to "-b" to have NIS servers use the domain name
+# resolver for hosts not in the current domain.
+#B=-b
+B=
+DIR =/etc
+#
+# If the ipnodes (IPv6 hosts file) lives in a directory other than
+# /etc/inet, then you'll need to change the following line.
+#
+INETDIR=/etc/inet
+#
+# If the audit_user, auth_attr, exec_attr, prof_attr files
+# live in a directory other than /etc/security, then you'll
+# need to change the following line.
+#
+RBACDIR=/etc/security
+#
+# If the passwd, shadow and/or adjunct files used by rpc.yppasswdd
+# live in directory other than /etc then you'll need to change the
+# following line.
+# DO NOT indent the line, however, since /etc/init.d/yp attempts
+# to find it with grep "^PWDIR" ...
+#
+PWDIR =/etc
+DOM = `domainname`
+NOPUSH = ""
+ALIASES = /etc/mail/aliases
+YPDIR=/usr/lib/netsvc/yp
+SBINDIR=/usr/sbin
+YPDBDIR=/var/yp
+YPPUSH=$(YPDIR)/yppush
+MAKEDBM=$(SBINDIR)/makedbm
+MULTI=$(YPDIR)/multi
+REVNETGROUP=$(SBINDIR)/revnetgroup
+STDETHERS=$(YPDIR)/stdethers
+STDHOSTS=$(YPDIR)/stdhosts
+MKNETID=$(SBINDIR)/mknetid
+MKALIAS=$(YPDIR)/mkalias
+
+CHKPIPE= || ( echo "NIS make terminated:" $@ 1>&2; kill -TERM 0 )
+
+
+k:
+ @if [ ! $(NOPUSH) ]; then $(MAKE) $(MFLAGS) -k all; \
+ else $(MAKE) $(MFLAGS) -k all NOPUSH=$(NOPUSH);fi
+
+all: passwd group hosts ipnodes ethers networks rpc services protocols \
+ netgroup bootparams aliases publickey netid netmasks c2secure \
+ timezone auto.master auto.home ageing \
+ auth.attr exec.attr prof.attr user.attr audit.user
+
+c2secure:
+ -@if [ -f $(PWDIR)/security/passwd.adjunct ]; then \
+ if [ ! $(NOPUSH) ]; then $(MAKE) $(MFLAGS) -k \
+ passwd.adjunct.time group.adjunct.time; \
+ else $(MAKE) $(MFLAGS) -k NOPUSH=$(NOPUSH) \
+ passwd.adjunct.time group.adjunct.time; \
+ fi; \
+ fi
+
+passwd.time: $(PWDIR)/passwd $(PWDIR)/shadow
+ -@if [ -f $(PWDIR)/security/passwd.adjunct ]; then \
+ (nawk 'BEGIN { FS=":"; OFS=":" } /^[a-zA-Z0-9_]/ { $$2 = "##" $$1; printf "%s\t%s\n", $$1, $$0 }' $(PWDIR)/passwd $(CHKPIPE)) | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/passwd.byname; \
+ (nawk 'BEGIN { FS=":"; OFS=":" } /^[a-zA-Z0-9_]/ { $$2 = "##" $$1; printf "%-10d\t%s\n", $$3, $$0 }' $(PWDIR)/passwd $(CHKPIPE)) | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/passwd.byuid; \
+ elif [ -f $(PWDIR)/shadow ]; then \
+ (nawk 'BEGIN { FS=":"; OFS=":"; while ( getline < "$(PWDIR)/shadow" > 0) shadow[$$1] = $$2; } /^[a-zA-Z0-9_]/ { $$2 = shadow[$$1]; printf "%s\t%s\n",$$1,$$0 }' $(PWDIR)/passwd $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/passwd.byname; \
+ (nawk 'BEGIN { FS=":"; OFS=":"; while ( getline < "$(PWDIR)/shadow" > 0) shadow[$$1] = $$2; } /^[a-zA-Z0-9_]/ { $$2 = shadow[$$1]; printf "%-10d\t%s\n",$$3,$$0 }' $(PWDIR)/passwd $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/passwd.byuid; \
+ else \
+ (awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { print $$1, $$0 }' $(PWDIR)/passwd $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/passwd.byname; \
+ (awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { printf("%-10d ", $$3); print $$0 }' $(PWDIR)/passwd $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/passwd.byuid; \
+ fi
+ @touch passwd.time;
+ @echo "updated passwd";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) passwd.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) passwd.byuid; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed passwd"; fi
+
+group.time: $(DIR)/group
+ @(awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { print $$1, $$0 }' $(DIR)/group $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/group.byname;
+ @(awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { printf("%-10d ", $$3); print $$0 }' $(DIR)/group $(CHKPIPE)) | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/group.bygid;
+ @touch group.time;
+ @echo "updated group";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) group.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) group.bygid; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed group"; fi
+
+project.time: $(DIR)/project
+ @(awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { print $$1, $$0 }' $(DIR)/project $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/project.byname;
+ @(awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { printf("%-10d ", $$2); print $$0 }' $(DIR)/project $(CHKPIPE)) | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/project.byprojid;
+ @touch project.time;
+ @echo "updated project";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) project.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) project.byprojid; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed project"; fi
+
+ipnodes.time: $(INETDIR)/ipnodes
+ @($(MULTI) -n $(B) -l $(INETDIR)/ipnodes);
+ @($(STDHOSTS) -wn $(INETDIR)/ipnodes $(CHKPIPE))| \
+ (awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$1, $$0 }' $(CHKPIPE)) | \
+ $(MAKEDBM) $(B) - $(YPDBDIR)/$(DOM)/ipnodes.byaddr;
+ @touch ipnodes.time;
+ @echo "updated ipnodes";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) ipnodes.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) ipnodes.byaddr; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed ipnodes"; fi
+
+hosts.time: $(DIR)/hosts
+ @($(MULTI) $(B) -l $(DIR)/hosts);
+ @($(STDHOSTS) -w $(DIR)/hosts $(CHKPIPE))| \
+ (awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$1, $$0 }' $(CHKPIPE)) | \
+ $(MAKEDBM) $(B) - $(YPDBDIR)/$(DOM)/hosts.byaddr;
+ @touch hosts.time;
+ @echo "updated hosts";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) hosts.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) hosts.byaddr; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed hosts"; fi
+
+ethers.time: $(DIR)/ethers
+ @($(STDETHERS) $(DIR)/ethers $(CHKPIPE)) \
+ |(awk '{print $$1, $$0; for (i = 3;i <= NF;i++) print $$i,$$0}' $(CHKPIPE)) \
+ | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/ethers.byaddr
+
+ @(awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$2, $$0 }' \
+ $(DIR)/ethers $(CHKPIPE)) | \
+ $(MAKEDBM) - $(YPDBDIR)/$(DOM)/ethers.byname;
+ @touch ethers.time;
+ @echo "updated ethers";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) ethers.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) ethers.byaddr; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed ethers"; fi
+
+networks.time: $(DIR)/networks
+ @(sed -e "/^#/d" -e s/#.*$$// $(DIR)/networks $(CHKPIPE)) |( awk \
+ '{print $$1, $$0; for (i = 3;i <= NF;i++) print $$i,$$0}' \
+ $(CHKPIPE) )| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/networks.byname;
+ @(awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$2, $$0 }' \
+ $(DIR)/networks $(CHKPIPE)) | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/networks.byaddr;
+ @touch networks.time;
+ @echo "updated networks";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) networks.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) networks.byaddr; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed networks"; fi
+
+services.time: $(DIR)/services
+ @(awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$2, $$0 }' \
+ $(DIR)/services $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/services.byname;
+ @(awk 'BEGIN { OFS="\t"; } \
+ $$1 !~ /^#/ { split($$2,pp,"/"); printf("%s/%s %s\n", $$1, pp[2], $$0);\
+ if (seen[$$1] == "") {\
+ printf("%s %s\n", $$1, $$0); seen[$$1]=$$1;} \
+ for (i = 3; i <= NF && $$i !~ /^#/; i++) {\
+ if (seen[$$i] == "") {\
+ printf("%s %s\n", $$i, $$0); seen[$$i]=$$i;} \
+ printf("%s/%s %s\n", $$i, pp[2], $$0)}}' \
+ $(DIR)/services $(CHKPIPE)) | \
+ $(MAKEDBM) $(B) - $(YPDBDIR)/$(DOM)/services.byservicename
+
+ @touch services.time;
+ @echo "updated services";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) services.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) services.byservicename; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed services"; fi
+
+rpc.time: $(DIR)/rpc
+ @(awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$2, $$0 }' \
+ $(DIR)/rpc $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/rpc.bynumber;
+ @touch rpc.time;
+ @echo "updated rpc";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) rpc.bynumber; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed rpc"; fi
+
+protocols.time: $(DIR)/protocols
+ @(awk 'BEGIN { OFS="\t"; } $$1 !~ /^#/ { print $$2, $$0 }' \
+ $(DIR)/protocols $(CHKPIPE)) | $(MAKEDBM) - \
+ $(YPDBDIR)/$(DOM)/protocols.bynumber;
+
+ @(sed -e "/^#/d" -e s/#.*$$// $(DIR)/protocols $(CHKPIPE)) |( awk \
+ '{print $$1,$$0; for (i = 3;i <= NF;i++) print $$i, $$0}' \
+ $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/protocols.byname;
+
+ @touch protocols.time;
+ @echo "updated protocols";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) protocols.byname; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) protocols.bynumber; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed protocols"; fi
+
+netgroup.time: $(DIR)/netgroup
+ @$(MAKEDBM) $(DIR)/netgroup $(YPDBDIR)/$(DOM)/netgroup
+ @($(REVNETGROUP) < $(DIR)/netgroup -u $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/netgroup.byuser
+ @($(REVNETGROUP) < $(DIR)/netgroup -h $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/netgroup.byhost
+ @touch netgroup.time;
+ @echo "updated netgroup";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) netgroup; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) netgroup.byuser; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) netgroup.byhost; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed netgroup"; fi
+
+bootparams.time: $(DIR)/bootparams
+ @(sed -e '/^#/d' -e s/#.*$$// -e 's/[ ][ ]*$$//' \
+ -e '/\\$$/s/\\$$/ /' $(DIR)/bootparams $(CHKPIPE))\
+ |( awk '/ $$/ {printf "%s", $$0} !/ $$/ {print}' $(CHKPIPE))\
+ |( sed -e 's/[ ][ ]*/ /g' $(CHKPIPE))\
+ | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/bootparams;
+ @touch bootparams.time;
+ @echo "updated bootparams";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) bootparams; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed bootparams"; fi
+
+aliases.time: $(ALIASES)
+ @cp $(ALIASES) $(YPDBDIR)/$(DOM)/mail.aliases;
+ @/usr/lib/sendmail -bi -oA$(YPDBDIR)/$(DOM)/mail.aliases;
+ $(MKALIAS) $(YPDBDIR)/$(DOM)/mail.aliases $(YPDBDIR)/$(DOM)/mail.byaddr;
+ @rm $(YPDBDIR)/$(DOM)/mail.aliases;
+ @touch aliases.time;
+ @echo "updated aliases";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) mail.aliases; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) mail.byaddr; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed aliases"; fi
+
+netmasks.time: $(DIR)/netmasks
+ $(MAKEDBM) $(DIR)/netmasks $(YPDBDIR)/$(DOM)/netmasks.byaddr;
+ @touch netmasks.time;
+ @echo "updated netmasks";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) netmasks.byaddr; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed netmasks"; fi
+
+
+publickey.time: $(DIR)/publickey
+ @(sed "/^#/d" < $(DIR)/publickey $(CHKPIPE))| $(MAKEDBM) - $(YPDBDIR)/$(DOM)/publickey.byname;
+ @touch publickey.time;
+ @echo "updated publickey";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) publickey.byname; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed publickey"; fi
+
+netid.time: $(PWDIR)/passwd $(DIR)/group $(DIR)/hosts $(DIR)/netid
+ @$(MKNETID) -q -p $(PWDIR)/passwd -g $(DIR)/group -h $(DIR)/hosts -m $(DIR)/netid > .ypjunk;
+ @$(MAKEDBM) .ypjunk $(YPDBDIR)/$(DOM)/netid.byname;
+ @rm -f .ypjunk;
+ @touch netid.time;
+ @echo "updated netid";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) netid.byname; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed netid"; fi
+
+# Old way. Could be restored by PSARC decision.
+#
+#passwd.adjunct.time: $(PWDIR)/security/passwd.adjunct
+# @(awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { print $$1, $$0 }' $(PWDIR)/security/passwd.adjunct $(CHKPIPE)) | \
+# $(MAKEDBM) -s - $(YPDBDIR)/$(DOM)/passwd.adjunct.byname;
+# @chmod 600 $(YPDBDIR)/$(DOM)/passwd.adjunct.byname.dir;
+# @chmod 600 $(YPDBDIR)/$(DOM)/passwd.adjunct.byname.pag;
+# @touch passwd.adjunct.time
+# @echo "updated passwd.adjunct";
+# @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) passwd.adjunct.byname; fi
+# @if [ ! $(NOPUSH) ]; then echo "pushed passwd.adjunct"; fi
+
+passwd.adjunct.time: $(PWDIR)/security/passwd.adjunct $(PWDIR)/shadow
+ -@if [ -f $(PWDIR)/shadow ]; then \
+ (nawk 'BEGIN { FS=":"; while (getline < "$(PWDIR)/shadow" > 0) shadow[$$1] = $$2; } /^[a-zA-Z0-9_]/ { $$2 = shadow[$$1]; OFS=":"; printf "%s\t%s\n", $$1, $$0 }' $(PWDIR)/security/passwd.adjunct $(CHKPIPE)) | $(MAKEDBM) -s - $(YPDBDIR)/$(DOM)/passwd.adjunct.byname; \
+ else \
+ (awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { print $$1, $$0 }' $(PWDIR)/security/passwd.adjunct $(CHKPIPE)) | \
+ $(MAKEDBM) -s - $(YPDBDIR)/$(DOM)/passwd.adjunct.byname; \
+ fi
+ @chmod 600 $(YPDBDIR)/$(DOM)/passwd.adjunct.byname.dir;
+ @chmod 600 $(YPDBDIR)/$(DOM)/passwd.adjunct.byname.pag;
+ @touch passwd.adjunct.time
+ @echo "updated passwd.adjunct";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) passwd.adjunct.byname; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed passwd.adjunct"; fi
+
+group.adjunct.time: $(PWDIR)/security/group.adjunct
+ @(awk 'BEGIN { FS=":"; OFS="\t"; } /^[a-zA-Z0-9_]/ { print $$1, $$0 }' $(PWDIR)/security/group.adjunct $(CHKPIPE)) | \
+ $(MAKEDBM) -s - $(YPDBDIR)/$(DOM)/group.adjunct.byname;
+ @chmod 600 $(YPDBDIR)/$(DOM)/group.adjunct.byname.dir;
+ @chmod 600 $(YPDBDIR)/$(DOM)/group.adjunct.byname.pag;
+ @touch group.adjunct.time
+ @echo "updated group.adjunct";
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) group.adjunct.byname; fi
+ @if [ ! $(NOPUSH) ]; then echo "pushed group.adjunct"; fi
+
+timezone.time: $(DIR)/timezone
+ -@if [ -f $(DIR)/timezone ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(DIR)/timezone \
+ | awk '{for (i = 2; i<=NF; i++) print $$i, $$0}' \
+ | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/timezone.byname; \
+ touch timezone.time; \
+ echo "updated timezone"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) timezone.byname; \
+ echo "pushed timezone"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(DIR)/timezone"; \
+ fi
+
+auto.master.time: $(DIR)/auto_master
+ -@if [ -f $(DIR)/auto_master ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(DIR)/auto_master \
+ | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/auto.master; \
+ touch auto.master.time; \
+ echo "updated auto.master"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) auto.master; \
+ echo "pushed auto.master"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(DIR)/auto_master"; \
+ fi
+
+auto.home.time: $(DIR)/auto_home
+ -@if [ -f $(DIR)/auto_home ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(DIR)/auto_home \
+ | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/auto.home; \
+ touch auto.home.time; \
+ echo "updated auto.home"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) auto.home; \
+ echo "pushed auto.home"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(DIR)/auto_home"; \
+ fi
+
+
+auth.attr.time: $(RBACDIR)/auth_attr
+ -@if [ -f $(RBACDIR)/auth_attr ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(RBACDIR)/auth_attr \
+ |sed -e '/\\$$/{:l' -e 'N;s/\\\n//;t h' -e ':h' \
+ -e 's/\\$$/\\/;t l' -e } \
+ | (nawk 'BEGIN { FS=":"; OFS=":" } /^[a-zA-Z0-9_]/ \
+ {printf "%s:%s\n", $$1, $$0 }' $(CHKPIPE)) \
+ | $(MAKEDBM) -S ":" -E - $(YPDBDIR)/$(DOM)/auth_attr; \
+ touch auth.attr.time; \
+ echo "updated auth_attr"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) auth_attr; \
+ echo "pushed auth_attr"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(RBACDIR)/auth_attr"; \
+ fi
+
+exec.attr.time: $(RBACDIR)/exec_attr
+ -@if [ -f $(RBACDIR)/exec_attr ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(RBACDIR)/exec_attr \
+ |sed -e '/\\$$/{:l' -e 'N;s/\\\n//;t h' -e ':h' \
+ -e 's/\\$$/\\/;t l' -e } \
+ | (nawk 'BEGIN { FS=":"; OFS=":" } /^[a-zA-Z0-9_]/ \
+ {printf "%s:%s:%s:%s\n", $$1, $$2, $$6, $$0 }' $(CHKPIPE)) \
+ | $(MAKEDBM) -S ":" -E -D 2 - $(YPDBDIR)/$(DOM)/exec_attr; \
+ touch exec.attr.time; \
+ echo "updated exec_attr"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) exec_attr; \
+ echo "pushed exec_attr"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(RBACDIR)/exec_attr"; \
+ fi
+
+prof.attr.time: $(RBACDIR)/prof_attr
+ -@if [ -f $(RBACDIR)/prof_attr ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(RBACDIR)/prof_attr \
+ |sed -e '/\\$$/{:l' -e 'N;s/\\\n//;t h' -e ':h' \
+ -e 's/\\$$/\\/;t l' -e } \
+ | (nawk 'BEGIN { FS=":"; OFS=":" } /^[a-zA-Z0-9_]/ \
+ {printf "%s:%s\n", $$1, $$0 }' $(CHKPIPE)) \
+ | $(MAKEDBM) -S ":" -E - $(YPDBDIR)/$(DOM)/prof_attr; \
+ touch prof.attr.time; \
+ echo "updated prof_attr"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) prof_attr; \
+ echo "pushed prof_attr"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(RBACDIR)/prof_attr"; \
+ fi
+
+user.attr.time: $(DIR)/user_attr
+ -@if [ -f $(DIR)/user_attr ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(DIR)/user_attr \
+ |sed -e '/\\$$/{:l' -e 'N;s/\\\n//;t h' -e ':h' \
+ -e 's/\\$$/\\/;t l' -e } \
+ | (nawk 'BEGIN { FS=":"; OFS=":" } /^[a-zA-Z0-9_]/ \
+ {printf "%s:%s\n", $$1, $$0 }' $(CHKPIPE)) \
+ | $(MAKEDBM) -S ":" -E - $(YPDBDIR)/$(DOM)/user_attr; \
+ touch user.attr.time; \
+ echo "updated user_attr"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) user_attr; \
+ echo "pushed user_attr"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(DIR)/user_attr"; \
+ fi
+
+audit.user.time: $(RBACDIR)/audit_user
+ -@if [ -f $(RBACDIR)/audit_user ]; then \
+ sed -e "/^#/d" -e s/#.*$$// $(RBACDIR)/audit_user \
+ |sed -e '/\\$$/{:l' -e 'N;s/\\\n//;t h' -e ':h' \
+ -e 's/\\$$/\\/;t l' -e } \
+ | (nawk 'BEGIN { FS=":"; OFS="\t" } /^[a-zA-Z0-9_]/ \
+ {print $$1, $$0 }' $(CHKPIPE)) \
+ | $(MAKEDBM) -s - $(YPDBDIR)/$(DOM)/audit_user; \
+ touch audit.user.time; \
+ echo "updated audit_user"; \
+ if [ ! $(NOPUSH) ]; then \
+ $(YPPUSH) audit_user; \
+ echo "pushed audit_user"; \
+ else \
+ : ; \
+ fi \
+ else \
+ echo "couldn't find $(RBACDIR)/audit_user"; \
+ fi
+
+ageing.time: $(PWDIR)/shadow
+ -@if [ -f $(PWDIR)/shadow ]; then \
+ (awk 'BEGIN {FS=":"; OFS=":"} $$1 !~ /^#/ {printf "%s\t%s:%s:%s:%s:%s:%s:%s:%s\n", $$1,$$1,$$3,$$4,$$5,$$6,$$7,$$8,$$9}' $(PWDIR)/shadow) | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/ageing.byname; \
+ touch ageing.time; \
+ echo "updated ageing"; \
+ else \
+ echo "couldn't find $(PWDIR)/shadow"; \
+ fi
+
+
+
+passwd: passwd.time
+group: group.time
+project: project.time
+hosts: hosts.time
+ipnodes: ipnodes.time
+ethers: ethers.time
+networks: networks.time
+rpc: rpc.time
+services: services.time
+protocols: protocols.time
+netgroup: netgroup.time
+bootparams: bootparams.time
+aliases: aliases.time
+publickey: publickey.time
+netid: netid.time
+passwd.adjunct: passwd.adjunct.time
+group.adjunct: group.adjunct.time
+netmasks: netmasks.time
+timezone: timezone.time
+auto.master: auto.master.time
+auto.home: auto.home.time
+auth.attr:auth.attr.time
+exec.attr:exec.attr.time
+prof.attr:prof.attr.time
+user.attr:user.attr.time
+audit.user:audit.user.time
+$(DIR)/netid:
+$(DIR)/timezone:
+$(DIR)/auto_master:
+$(DIR)/auto_home:
+$(PWDIR)/shadow:
+$(DIR)/auth_attr:
+$(DIR)/exec_attr:
+$(DIR)/prof_attr:
+$(DIR)/user_attr:
+$(DIR)/audit_user:
+ageing: ageing.time
diff --git a/usr/src/cmd/ypcmd/net_files/aliases b/usr/src/cmd/ypcmd/net_files/aliases
new file mode 100644
index 0000000000..79d79ed3b4
--- /dev/null
+++ b/usr/src/cmd/ypcmd/net_files/aliases
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 1992 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+# Aliases file- database of full length and truncated length domain and
+#map names. Accessed by YP commands.
diff --git a/usr/src/cmd/ypcmd/net_files/netid b/usr/src/cmd/ypcmd/net_files/netid
new file mode 100644
index 0000000000..7c2c5823f5
--- /dev/null
+++ b/usr/src/cmd/ypcmd/net_files/netid
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 1992 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#ident "%Z%%M% %I% %E% SMI"
+
+# Netid database
diff --git a/usr/src/cmd/ypcmd/net_files/nicknames b/usr/src/cmd/ypcmd/net_files/nicknames
new file mode 100644
index 0000000000..fbb8745c5b
--- /dev/null
+++ b/usr/src/cmd/ypcmd/net_files/nicknames
@@ -0,0 +1,10 @@
+passwd passwd.byname
+group group.byname
+project project.byname
+networks networks.byaddr
+hosts hosts.byname
+ipnodes ipnodes.byname
+protocols protocols.bynumber
+services services.byname
+aliases mail.aliases
+ethers ethers.byname
diff --git a/usr/src/cmd/ypcmd/net_files/publickey b/usr/src/cmd/ypcmd/net_files/publickey
new file mode 100644
index 0000000000..dd81478400
--- /dev/null
+++ b/usr/src/cmd/ypcmd/net_files/publickey
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+# Public Key Database
+#
+# To add an entry to this file, an administrator should use the command
+# newkey(1M) on the local machine.
+# Non root users are not allowed to change their key-pair in this file.
+# Entries in this file are only available to services on the local host
+# and can be compromised. Hence, we recommend that Users store their
+# secure rpc keys in NIS or NIS+.
+#
+# The syntax is:
+# netname public_key:encrypted_private_key
+#
+nobody c3d91f44568fbbefada50d336d9bd67b16e7016f987bb607:7675cd9b8753b5db09dabf12da759c2bd1331c927bb322861fffb54be13f55e9
+#
diff --git a/usr/src/cmd/ypcmd/net_files/updaters b/usr/src/cmd/ypcmd/net_files/updaters
new file mode 100644
index 0000000000..f74987d4ec
--- /dev/null
+++ b/usr/src/cmd/ypcmd/net_files/updaters
@@ -0,0 +1,42 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 1989 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+#
+# Portions of this source code were derived from Berkeley 4.3 BSD
+# under license from the Regents of the University of California.
+#
+# Update file for yellow pages
+
+#ident "%Z%%M% %I% %E% SMI"
+
+# where the yp files live
+DIR=/etc
+# where the yp binaries live
+EXEDIR=/usr/lib/netsvc/yp
+
+publickey.byname:
+ -@$(EXEDIR)/udpublickey $(DIR)/publickey "make publickey"; \
+ echo $$?
diff --git a/usr/src/cmd/ypcmd/nick.c b/usr/src/cmd/ypcmd/nick.c
new file mode 100644
index 0000000000..4ebf413233
--- /dev/null
+++ b/usr/src/cmd/ypcmd/nick.c
@@ -0,0 +1,112 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1992 by Sun Microsystems Inc.
+ */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAXMAPS 500
+/* number of nickname file entries arbitrarily limited */
+
+static char NICKFILE[] = "/var/yp/nicknames";
+static char *transtable[MAXMAPS];
+
+/*
+ * This will read nicknames from file /var/yp/nicknames
+ * and print it out or save it for future use.
+ */
+void
+maketable(dump)
+int dump;
+{
+ FILE *nickp;
+ int i = 0;
+ char nickbuf[2*YPMAXMAP+3], nickname[YPMAXMAP+1], mapname[YPMAXMAP+1];
+
+ if ((nickp = fopen(NICKFILE, "r")) == NULL) {
+ (void) fprintf(stderr, "nickname file %s does not exist\n",
+ NICKFILE);
+ exit(1);
+ }
+ while (fgets(nickbuf, YPMAXMAP, nickp) != NULL) {
+ if (strchr(nickbuf, '\n') == NULL) {
+ (void) fprintf(stderr,
+ "garbled nickname file %s\n", NICKFILE);
+ exit(1);
+ }
+ (void) memset(nickname, 0, YPMAXMAP+1);
+ (void) memset(mapname, 0, YPMAXMAP+1);
+ if (sscanf(nickbuf, "%s %s\n", nickname, mapname) != 2) {
+ (void) fprintf(stderr,
+ "garbled nickname file %s\n", NICKFILE);
+ exit(1);
+ }
+ if (!dump) {
+ transtable[i] = strdup(nickname);
+ transtable[i+1] = strdup(mapname);
+ i += 2;
+ transtable[i] = NULL;
+ } else {
+ printf("Use \"%s\"\tfor map \"%s\"\n",
+ nickname, mapname);
+ }
+ }
+ fclose(nickp);
+}
+
+/*
+ * This will get the mapname for a given nickname from the file.
+ */
+int
+getmapname(nick, map)
+char *nick, *map;
+{
+ FILE *nickp;
+ char nickbuf[2*YPMAXMAP+3], nickname[YPMAXMAP+1];
+
+ if ((nickp = fopen(NICKFILE, "r")) == NULL)
+ return (0);
+ while (fgets(nickbuf, YPMAXMAP, nickp) != NULL) {
+ if (strchr(nickbuf, '\n') == NULL) {
+ fclose(nickp);
+ return (0);
+ }
+ (void) memset(nickname, 0, YPMAXMAP+1);
+ (void) memset(map, 0, YPMAXMAP+1);
+ if (sscanf(nickbuf, "%s %s\n", nickname, map) != 2) {
+ fclose(nickp);
+ return (0);
+ }
+ if (strcmp(nick, nickname) == 0) {
+ fclose(nickp);
+ return (1);
+ }
+ }
+ fclose(nickp);
+ return (0);
+}
diff --git a/usr/src/cmd/ypcmd/revnetgroup/Makefile b/usr/src/cmd/ypcmd/revnetgroup/Makefile
new file mode 100644
index 0000000000..174fd0bee0
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/Makefile
@@ -0,0 +1,59 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1996, 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PROG = revnetgroup
+
+include ../../Makefile.cmd
+
+OBJS = revnetgroup.o getgroup.o table.o util.o
+SRCS = $(OBJS:.o=.c)
+HDRS = getgroup.h table.h util.h
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTUSRSBINPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+ ${LINT.c} ${SRCS}
+
+cstyle:
+ ${CSTYLE} ${SRCS}
+
+clobber: clean
+ $(RM) $(PROG)
+
+FRC:
diff --git a/usr/src/cmd/ypcmd/revnetgroup/getgroup.c b/usr/src/cmd/ypcmd/revnetgroup/getgroup.c
new file mode 100644
index 0000000000..7a48de096a
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/getgroup.c
@@ -0,0 +1,249 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1996, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.5 */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "table.h"
+#include "util.h"
+#include "getgroup.h"
+
+#define MAXGROUPLEN 1024
+
+/*
+ * Stolen mostly, from getnetgrent.c
+ *
+ * my_getgroup() performs the same function as _getgroup(), but operates
+ * on /etc/netgroup directly, rather than doing yp lookups.
+ *
+ * /etc/netgroup must first loaded into a hash table so the matching
+ * function can look up lines quickly.
+ */
+
+
+/* To check for cycles in netgroups */
+struct list {
+ char *name;
+ struct list *nxt;
+};
+
+
+extern stringtable ngtable; /* stored info from /etc/netgroup */
+
+static struct grouplist *grouplist; /* stores a list of users in a group */
+
+static char *any();
+static char *match();
+static char *fill();
+static void freegrouplist();
+static void doit();
+
+
+
+static void
+freegrouplist()
+{
+ struct grouplist *gl;
+
+ for (gl = grouplist; gl != NULL; gl = gl->gl_nxt) {
+ FREE(gl->gl_name);
+ FREE(gl->gl_domain);
+ FREE(gl->gl_machine);
+ FREE(gl);
+ }
+ grouplist = NULL;
+}
+
+
+
+
+struct grouplist *
+my_getgroup(group)
+ char *group;
+{
+ freegrouplist();
+ doit(group, (struct list *) NULL);
+ return (grouplist);
+}
+
+
+
+
+
+/*
+ * recursive function to find the members of netgroup "group". "list" is
+ * the path followed through the netgroups so far, to check for cycles.
+ */
+static void
+doit(group, list)
+ char *group;
+ struct list *list;
+{
+ register char *p, *q;
+ register struct list *ls;
+ struct list tmplist;
+ char *val;
+ struct grouplist *gpls;
+
+
+ /*
+ * check for non-existing groups
+ */
+ if ((val = match(group)) == NULL) {
+ return;
+ }
+
+
+ /*
+ * check for cycles
+ */
+ for (ls = list; ls != NULL; ls = ls->nxt) {
+ if (strcmp(ls->name, group) == 0) {
+ (void) fprintf(stderr,
+ "Cycle detected in /etc/netgroup: %s.\n",
+ group);
+ return;
+ }
+ }
+
+
+ ls = &tmplist;
+ ls->name = group;
+ ls->nxt = list;
+ list = ls;
+
+ p = val;
+ while (p != NULL) {
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == EOS || *p == '#')
+ break;
+ if (*p == '(') {
+ gpls = MALLOC(struct grouplist);
+ p++;
+
+ if (!(p = fill(p, &gpls->gl_machine, ','))) {
+ goto syntax_error;
+ }
+ if (!(p = fill(p, &gpls->gl_name, ','))) {
+ goto syntax_error;
+ }
+ if (!(p = fill(p, &gpls->gl_domain, ')'))) {
+ goto syntax_error;
+ }
+ gpls->gl_nxt = grouplist;
+ grouplist = gpls;
+ } else {
+ q = any(p, " \t\n#");
+ if (q && *q == '#')
+ break;
+ *q = EOS;
+ doit(p, list);
+ *q = ' ';
+ }
+ p = any(p, " \t");
+ }
+ return;
+
+syntax_error:
+ (void) fprintf(stderr, "syntax error in /etc/netgroup\n");
+ (void) fprintf(stderr, "--- %s %s\n", group, val);
+}
+
+
+
+
+/*
+ * Fill a buffer "target" selectively from buffer "start".
+ * "termchar" terminates the information in start, and preceding
+ * or trailing white space is ignored. If the buffer "start" is
+ * empty, "target" is filled with "*". The location just after the
+ * terminating character is returned.
+ */
+static char *
+fill(start, target, termchar)
+ char *start;
+ char **target;
+ char termchar;
+{
+ register char *p;
+ register char *q;
+ register char *r;
+ int size;
+
+ for (p = start; *p == ' ' || *p == '\t'; p++)
+ ;
+ r = strchr(p, termchar);
+ if (r == (char *)NULL) {
+ return ((char *)NULL);
+ }
+ if (p == r) {
+ *target = NULL;
+ } else {
+ for (q = r-1; *q == ' ' || *q == '\t'; q--)
+ ;
+ size = q-p+1;
+ STRNCPY(*target, p, size);
+ }
+ return (r+1);
+}
+
+
+/*
+ * scans cp, looking for a match with any character
+ * in match. Returns pointer to place in cp that matched
+ * (or NULL if no match)
+ */
+static char *
+any(cp, match)
+ register char *cp;
+ char *match;
+{
+ register char *mp, c;
+
+ while (c = *cp) {
+ for (mp = match; *mp; mp++)
+ if (*mp == c)
+ return (cp);
+ cp++;
+ }
+ return (NULL);
+}
+
+
+
+/*
+ * The equivalent of yp_match. Returns the match, or NULL if there is none.
+ */
+static char *
+match(group)
+ char *group;
+{
+ return (lookup(ngtable, group));
+}
diff --git a/usr/src/cmd/ypcmd/revnetgroup/getgroup.h b/usr/src/cmd/ypcmd/revnetgroup/getgroup.h
new file mode 100644
index 0000000000..6c1ab0ed2d
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/getgroup.h
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1995 Sun Microsystems Inc.
+ * All rights reserved.
+ */
+
+
+#ifndef __GETGROUP_H
+#define __GETGROUP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.4 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct grouplist {
+ char *gl_machine;
+ char *gl_name;
+ char *gl_domain;
+ struct grouplist *gl_nxt;
+};
+
+struct grouplist *my_getgroup();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GETGROUP_H */
diff --git a/usr/src/cmd/ypcmd/revnetgroup/revnetgroup.c b/usr/src/cmd/ypcmd/revnetgroup/revnetgroup.c
new file mode 100644
index 0000000000..41f161e913
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/revnetgroup.c
@@ -0,0 +1,299 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*
+ * For SUNWnskit - version 1.1
+ *
+ * Based on:
+ * #pragma ident "%Z%%M% %I% %E% SMI" (SMI4.1 1.6)
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <rpcsvc/ypclnt.h>
+#include "util.h"
+#include "table.h"
+#include "getgroup.h"
+
+#define MAXDOMAINLEN 256
+#define MAXGROUPLEN 1024
+
+/*
+ * Reverse the netgroup file. A flag of "-u" means reverse by username,
+ * one of "-h" means reverse by hostname. Each line in the output file
+ * will begin with a key formed by concatenating the host or user name
+ * with the domain name. The key will be followed by a tab, then the
+ * comma-separated, newline-terminated list of groups to which the
+ * user or host belongs.
+ *
+ * Exception: Groups to which everyone belongs (universal groups) will
+ * not be included in the list. The universal groups will be listed under
+ * the special name "*".
+ *
+ * Thus to find out all the groups that user "foo" of domain "bar" is in,
+ * lookup the groups under foo.bar, foo.*, *.bar and *.*.
+ *
+ */
+
+
+
+/* Stores a list of strings */
+typedef struct stringnode *stringlist;
+struct stringnode {
+ char *str;
+ stringlist next;
+};
+typedef struct stringnode stringnode;
+
+
+
+/* Stores a list of (name,list-of-groups) */
+typedef struct groupentrynode *groupentrylist;
+struct groupentrynode {
+ char *name;
+ stringlist groups;
+ groupentrylist next;
+};
+typedef struct groupentrynode groupentrynode;
+
+stringtable ngtable;
+
+static groupentrylist grouptable[TABLESIZE];
+
+static char *nextgroup(void);
+static void storegroup(char *group, struct grouplist *glist, int byuser);
+static void enter(char *name, char *group);
+static void appendgroup(groupentrylist grlist, char *group);
+static groupentrylist newentry(char *name, char *group);
+static void loadtable(FILE *nf);
+static void dumptable(void);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *group;
+ struct grouplist *glist;
+ int byuser;
+
+ loadtable(stdin);
+ if (argc == 2 && argv[1][0] == '-' &&
+ (argv[1][1] == 'u' || argv[1][1] == 'h')) {
+ byuser = (argv[1][1] == 'u');
+ } else {
+ (void) fprintf(stderr,
+ "usage: %s -h (by host), %s -u (by user)\n",
+ argv[0], argv[0]);
+ exit(1);
+ }
+
+ while (group = nextgroup()) {
+ glist = my_getgroup(group);
+ storegroup(group, glist, byuser);
+ }
+ dumptable();
+
+ return (0);
+}
+
+/*
+ * Get the next netgroup from /etc/netgroup
+ */
+static char *
+nextgroup(void)
+{
+ static int index = -1;
+ static tablelist cur = NULL;
+ char *group;
+
+ while (cur == NULL) {
+ if (++index == TABLESIZE) {
+ return (NULL);
+ }
+ cur = ngtable[index];
+ }
+ group = cur->key;
+ cur = cur->next;
+ return (group);
+}
+
+
+
+/*
+ * Dump out all of the stored info into a file
+ */
+static void
+dumptable(void)
+{
+ int i;
+ groupentrylist entry;
+ stringlist groups;
+
+ for (i = 0; i < TABLESIZE; i++) {
+ if (entry = grouptable[i]) {
+ while (entry) {
+ fputs(entry->name, stdout);
+ putc('\t', stdout);
+ for (groups = entry->groups; groups;
+ groups = groups->next) {
+ fputs(groups->str, stdout);
+ if (groups->next) {
+ putc(',', stdout);
+ }
+ }
+ putc('\n', stdout);
+ entry = entry->next;
+ }
+ }
+ }
+}
+
+
+
+
+/*
+ * Add a netgroup to a user's list of netgroups
+ */
+static void
+storegroup(char *group, struct grouplist *glist, int byuser)
+{
+ char *name; /* username or hostname */
+ char *domain;
+ char *key;
+ static char *universal = "*";
+
+ for (; glist; glist = glist->gl_nxt) {
+ name = byuser ? glist->gl_name : glist->gl_machine;
+ if (!name) {
+ name = universal;
+ } else if (!isalnum(*name) && *name != '_') {
+ continue;
+ }
+ domain = glist->gl_domain;
+ if (!domain) {
+ domain = universal;
+ }
+ key = malloc((unsigned) (strlen(name)+strlen(domain)+2));
+ (void) sprintf(key, "%s.%s", name, domain);
+ enter(key, group);
+ }
+}
+
+
+
+static groupentrylist
+newentry(char *name, char *group)
+{
+ groupentrylist new;
+
+ new = MALLOC(groupentrynode);
+
+ STRCPY(new->name, name);
+
+ new->groups = MALLOC(stringnode);
+ new->groups->str = group;
+ new->groups->next = NULL;
+
+ new->next = NULL;
+ return (new);
+}
+
+static void
+appendgroup(groupentrylist grlist, char *group)
+{
+ stringlist cur, prev;
+
+ for (cur = grlist->groups; cur; prev = cur, cur = cur->next) {
+ if (strcmp(group, cur->str) == 0) {
+ return;
+ }
+ }
+ prev->next = MALLOC(stringnode);
+ cur = prev->next;
+ cur->str = group;
+ cur->next = NULL;
+}
+
+static void
+enter(char *name, char *group)
+{
+ int key;
+ groupentrylist gel;
+ groupentrylist gelprev;
+
+ key = tablekey(name);
+ if (grouptable[key] == NULL) {
+ grouptable[key] = newentry(name, group);
+ } else {
+ gel = grouptable[key];
+ while (gel && strcmp(gel->name, name)) {
+ gelprev = gel;
+ gel = gel->next;
+ }
+ if (gel) {
+ appendgroup(gel, group);
+ } else {
+ gelprev->next = newentry(name, group);
+ }
+ }
+}
+
+/*
+ * Load up a hash table with the info in /etc/netgroup
+ */
+static void
+loadtable(FILE *nf)
+{
+ char buf[MAXGROUPLEN];
+ char *p;
+ char *group;
+ char *line;
+
+ while (getline(buf, MAXGROUPLEN, nf)) {
+ for (p = buf; *p && isspace((int)*p); p++)
+ ; /* skip leading blanks */
+ for (; *p && *p != '#' && *p != ' ' && *p != '\t'; p++)
+ ;
+ if (*p == EOS || *p == '#')
+ continue;
+ *p++ = EOS;
+
+ while (*p == ' ' || *p == '\t') {
+ p++;
+ }
+ if (*p == EOS || *p == '#')
+ continue;
+
+ STRCPY(group, buf);
+ STRCPY(line, p);
+ store(ngtable, group, line);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/revnetgroup/table.c b/usr/src/cmd/ypcmd/revnetgroup/table.c
new file mode 100644
index 0000000000..140b213e38
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/table.c
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1994, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.4 */
+
+#include <ctype.h>
+#include "util.h"
+#include "table.h"
+
+
+
+/*
+ * Hash table manager. Store/lookup strings, keyed by string
+ */
+
+/*
+ * Generate the key into the table using the first two letters
+ * of "str". The table is alphabetized, with no distinction between
+ * upper and lower case. Non-letters are given least significance.
+ */
+int
+tablekey(str)
+ register char *str;
+{
+#define TOLOWER(c) (islower(c) ? c : \
+ (isupper(c) ? tolower(c) : ('a'+NUMLETTERS-1)))
+
+ register int c1, c2;
+
+ c1 = *str++;
+ c2 = *str;
+ if (c1 == EOS) {
+ c2 = EOS; /* just in case */
+ }
+ c1 = TOLOWER(c1) - 'a';
+ c2 = TOLOWER(c2) - 'a';
+ return (c1*NUMLETTERS + c2);
+}
+
+
+void
+store(table, key, datum)
+ stringtable table;
+ char *key;
+ char *datum;
+{
+ int index;
+ tablelist cur, new;
+
+ index = tablekey(key);
+ cur = table[index];
+
+ new = MALLOC(tablenode);
+ new->key = key;
+ new->datum = datum;
+ new->next = cur;
+ table[index] = new;
+}
+
+
+char *
+lookup(table, key)
+ stringtable table;
+ char *key;
+{
+ tablelist cur;
+
+ cur = table[tablekey(key)];
+ while (cur && strcmp(cur->key, key)) {
+ cur = cur->next;
+ }
+ if (cur) {
+ return (cur->datum);
+ } else {
+ return (NULL);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/revnetgroup/table.h b/usr/src/cmd/ypcmd/revnetgroup/table.h
new file mode 100644
index 0000000000..8c304a0dda
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/table.h
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1995 Sun Microsystems Inc.
+ * All rights reserved.
+ */
+
+
+#ifndef __TABLE_H
+#define __TABLE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.4 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NUMLETTERS 27 /* 26 letters + 1 for anything else */
+#define TABLESIZE (NUMLETTERS*NUMLETTERS)
+
+typedef struct tablenode *tablelist;
+struct tablenode {
+ char *key;
+ char *datum;
+ tablelist next;
+};
+typedef struct tablenode tablenode;
+
+typedef tablelist stringtable[TABLESIZE];
+
+int tablekey();
+char *lookup();
+void store();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TABLE_H */
diff --git a/usr/src/cmd/ypcmd/revnetgroup/util.c b/usr/src/cmd/ypcmd/revnetgroup/util.c
new file mode 100644
index 0000000000..511bf34b5b
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/util.c
@@ -0,0 +1,112 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.4 */
+
+#include <stdio.h>
+#include <string.h>
+#include "util.h"
+
+
+
+
+/*
+ * This is just like fgets, but recognizes that "\\n" signals a continuation
+ * of a line
+ */
+char *
+getline(line, maxlen, fp)
+ char *line;
+ int maxlen;
+ FILE *fp;
+{
+ register char *p;
+ register char *start;
+ int c;
+
+ start = line;
+
+nextline:
+ if (fgets(start, maxlen, fp) == NULL) {
+ return (NULL);
+ }
+ for (p = start; *p; p++) {
+ if (*p == '\n') {
+ if (p > start && *(p-1) == '\\') {
+ start = p - 1;
+ maxlen++;
+ goto nextline;
+ } else {
+ return (line);
+ }
+ }
+ maxlen--;
+ }
+
+ /*
+ * Input line is too long. Rest of the line needs to be discarded.
+ * Reinsert the last char into the stream. This is done so that
+ * in case the last char read is '\' and it is followed by a '\n'
+ * then the next line too can be discarded.
+ */
+ if (p > start)
+ (void) ungetc(*(p-1), fp);
+
+ /*
+ * Discard the rest of the line
+ */
+ while ((c = getc(fp)) != EOF) {
+ if (c == '\n')
+ break;
+ else if (c == '\\') {
+ /*
+ * Ignore the next character except EOF
+ */
+ if (getc(fp) == EOF)
+ break;
+ }
+ }
+
+ maxlen = strlen(line) + 1;
+
+ /*
+ * Certain functions expects a newline in the buffer.
+ */
+ if (maxlen >= 2)
+ line[maxlen - 2] = '\n';
+ (void) fprintf(stderr, "Following line too long - remaining chars "
+ "ignored\n--- %s", line);
+ return (line);
+}
+
+
+void
+fatal(message)
+ char *message;
+{
+ (void) fprintf(stderr, "fatal error: %s\n", message);
+ exit(1);
+}
diff --git a/usr/src/cmd/ypcmd/revnetgroup/util.h b/usr/src/cmd/ypcmd/revnetgroup/util.h
new file mode 100644
index 0000000000..e83ba1ed0f
--- /dev/null
+++ b/usr/src/cmd/ypcmd/revnetgroup/util.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1995 Sun Microsystems Inc.
+ * All rights reserved.
+ */
+
+
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.5 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EOS '\0'
+
+#ifndef NULL
+# define NULL ((char *) 0)
+#endif
+
+
+#define MALLOC(object_type) ((object_type *) malloc(sizeof(object_type)))
+
+#define FREE(ptr) free((char *) ptr)
+
+#define STRCPY(dst,src) \
+ (dst = malloc((unsigned)strlen(src)+1), (void) strcpy(dst,src))
+
+#define STRNCPY(dst,src,num) \
+ (dst = (char *) malloc((unsigned)(num) + 1),\
+ (void)strncpy(dst,src,num),(dst)[num] = EOS)
+
+/*
+extern char *malloc();
+*/
+extern char *alloca();
+
+char *getline();
+void fatal();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTIL_H */
diff --git a/usr/src/cmd/ypcmd/rpc_bootstrap.c b/usr/src/cmd/ypcmd/rpc_bootstrap.c
new file mode 100644
index 0000000000..ae3737494f
--- /dev/null
+++ b/usr/src/cmd/ypcmd/rpc_bootstrap.c
@@ -0,0 +1,484 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <tiuser.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdir.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/nis.h>
+
+CLIENT *__clnt_tp_create_bootstrap();
+int __rpcb_getaddr_bootstrap();
+struct hostent *__files_gethostbyname();
+
+extern int hostNotKnownLocally;
+
+static char *__map_addr();
+
+/*
+ * __clnt_tp_create_bootstrap()
+ *
+ * This routine is NOT TRANSPORT INDEPENDENT.
+ *
+ * It relies on the local /etc/hosts file for hostname to address
+ * translation and does it itself instead of calling netdir_getbyname
+ * thereby avoids recursion.
+ */
+CLIENT *
+__clnt_tp_create_bootstrap(hostname, prog, vers, nconf)
+ char *hostname;
+ u_long prog, vers;
+ struct netconfig *nconf;
+{
+ CLIENT *cl;
+ struct netbuf *svc_taddr;
+ struct sockaddr_in6 *sa;
+ int fd;
+
+ if (nconf == (struct netconfig *)NULL) {
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (NULL);
+ }
+ if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
+ rpc_createerr.cf_stat = RPC_TLIERROR;
+ return (NULL);
+ }
+ svc_taddr = (struct netbuf *) malloc(sizeof (struct netbuf));
+ if (! svc_taddr) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ t_close(fd);
+ return (NULL);
+ }
+ sa = (struct sockaddr_in6 *)calloc(1, sizeof (*sa));
+ if (! sa) {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ t_close(fd);
+ free(svc_taddr);
+ return (NULL);
+ }
+ svc_taddr->maxlen = svc_taddr->len = sizeof (*sa);
+ svc_taddr->buf = (char *)sa;
+ if (__rpcb_getaddr_bootstrap(prog,
+ vers, nconf, svc_taddr, hostname) == FALSE) {
+ t_close(fd);
+ free(svc_taddr);
+ free(sa);
+ return (NULL);
+ }
+ rpc_createerr.cf_stat = RPC_SUCCESS;
+ cl = __nis_clnt_create(fd, nconf, 0, svc_taddr, 0, prog, vers, 0, 0);
+ if (cl == 0) {
+ if (rpc_createerr.cf_stat == RPC_SUCCESS)
+ rpc_createerr.cf_stat = RPC_TLIERROR;
+ t_close(fd);
+ }
+ free(svc_taddr);
+ free(sa);
+ return (cl);
+}
+
+/*
+ * __rpcb_getaddr_bootstrap()
+ *
+ * This is our internal function that replaces rpcb_getaddr(). We
+ * build our own to prevent calling netdir_getbyname() which could
+ * recurse to the nameservice.
+ */
+int
+__rpcb_getaddr_bootstrap(program, version, nconf, address, hostname)
+ u_long program;
+ u_long version;
+ struct netconfig *nconf;
+ struct netbuf *address; /* populate with the taddr of the service */
+ char *hostname;
+{
+ char *svc_uaddr;
+ struct hostent *hent;
+ struct sockaddr_in *sa;
+ struct sockaddr_in6 *sa6;
+ struct netbuf rpcb_taddr;
+ struct sockaddr_in local_sa;
+ struct sockaddr_in6 local_sa6;
+ in_port_t inport;
+ int p1, p2;
+ char *ipaddr, *port;
+ int i, ipaddrlen;
+
+ if (strcmp(nconf->nc_protofmly, NC_INET) != 0 &&
+ strcmp(nconf->nc_protofmly, NC_INET6) != 0) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+ return (FALSE);
+ }
+
+ /* Get the address of the RPCBIND at hostname */
+ hent = __files_gethostbyname(hostname, nconf->nc_protofmly);
+ if (hent == (struct hostent *)NULL) {
+ rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+ hostNotKnownLocally = 1;
+ return (FALSE);
+ }
+
+ switch (hent->h_addrtype) {
+ case AF_INET:
+ local_sa.sin_family = AF_INET;
+ local_sa.sin_port = htons(111); /* RPCBIND port */
+ memcpy((char *)&(local_sa.sin_addr.s_addr),
+ hent->h_addr_list[0], hent->h_length);
+ rpcb_taddr.buf = (char *)&local_sa;
+ rpcb_taddr.maxlen = sizeof (local_sa);
+ rpcb_taddr.len = rpcb_taddr.maxlen;
+ break;
+ case AF_INET6:
+ local_sa6.sin6_family = AF_INET6;
+ local_sa6.sin6_port = htons(111); /* RPCBIND port */
+ memcpy((char *)&(local_sa6.sin6_addr.s6_addr),
+ hent->h_addr_list[0], hent->h_length);
+ rpcb_taddr.buf = (char *)&local_sa6;
+ rpcb_taddr.maxlen = sizeof (local_sa6);
+ rpcb_taddr.len = rpcb_taddr.maxlen;
+ break;
+ default:
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (FALSE);
+ }
+
+ svc_uaddr = __map_addr(nconf, &rpcb_taddr, program, version);
+ if (! svc_uaddr)
+ return (FALSE);
+
+/* do a local uaddr2taddr and stuff in the memory supplied by the caller */
+ ipaddr = svc_uaddr;
+ ipaddrlen = strlen(ipaddr);
+ /* Look for the first '.' starting from the end */
+ for (i = ipaddrlen-1; i >= 0; i--)
+ if (ipaddr[i] == '.') break;
+ /* Find the second dot (still counting from the end) */
+ for (i--; i >= 0; i--)
+ if (ipaddr[i] == '.') break;
+ /* If we didn't find it, the uaddr has a syntax error */
+ if (i < 0) {
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (FALSE);
+ }
+ port = &ipaddr[i+1];
+ ipaddr[i] = '\0';
+ sscanf(port, "%d.%d", &p1, &p2);
+ inport = (p1 << 8) + p2;
+ if (hent->h_addrtype == AF_INET) {
+ sa = (struct sockaddr_in *)address->buf;
+ address->len = sizeof (*sa);
+ if (inet_pton(AF_INET, ipaddr, &sa->sin_addr) != 1) {
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (FALSE);
+ }
+ sa->sin_port = htons(inport);
+ sa->sin_family = AF_INET;
+ } else {
+ sa6 = (struct sockaddr_in6 *)address->buf;
+ address->len = sizeof (*sa6);
+ if (inet_pton(AF_INET6, ipaddr, &sa6->sin6_addr) != 1) {
+ rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+ return (FALSE);
+ }
+ sa6->sin6_port = htons(inport);
+ sa6->sin6_family = AF_INET6;
+ }
+ return (TRUE);
+}
+
+/*
+ * __map_addr()
+ *
+ */
+static char *
+__map_addr(nc, rpcb_taddr, prog, ver)
+ struct netconfig *nc; /* Our transport */
+ struct netbuf *rpcb_taddr; /* RPCBIND address */
+ u_long prog, ver; /* Name service Prog/vers */
+{
+ register CLIENT *client;
+ RPCB parms; /* Parameters for RPC binder */
+ enum clnt_stat clnt_st; /* Result from the rpc call */
+ int fd; /* Stream file descriptor */
+ char *ua = NULL; /* Universal address of service */
+ struct timeval tv; /* Timeout for our rpcb call */
+
+ /*
+ * First we open a connection to the remote rpcbind process.
+ */
+ if ((fd = t_open(nc->nc_device, O_RDWR, NULL)) == -1) {
+ rpc_createerr.cf_stat = RPC_TLIERROR;
+ return (NULL);
+ }
+
+ client = __nis_clnt_create(fd, nc, 0, rpcb_taddr, 0,
+ RPCBPROG, RPCBVERS, 0, 0);
+ if (! client) {
+ t_close(fd);
+ rpc_createerr.cf_stat = RPC_TLIERROR;
+ return (NULL);
+ }
+
+ /*
+ * Now make the call to get the NIS service address.
+ */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ parms.r_prog = prog;
+ parms.r_vers = ver;
+ parms.r_netid = nc->nc_netid; /* not needed */
+ parms.r_addr = ""; /* not needed; just for xdring */
+ parms.r_owner = ""; /* not needed; just for xdring */
+ clnt_st = clnt_call(client, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms,
+ xdr_wrapstring, (char *)&ua, tv);
+
+ rpc_createerr.cf_stat = clnt_st;
+ if (clnt_st == RPC_SUCCESS) {
+
+ clnt_destroy(client);
+ t_close(fd);
+ if (*ua == '\0') {
+ xdr_free(xdr_wrapstring, (char *)&ua);
+ return (NULL);
+ }
+ return (ua);
+ } else if (((clnt_st == RPC_PROGVERSMISMATCH) ||
+ (clnt_st == RPC_PROGUNAVAIL) ||
+ (clnt_st == RPC_TIMEDOUT)) &&
+ (strcmp(nc->nc_protofmly, NC_INET) == 0)) {
+ /*
+ * version 3 not available. Try version 2
+ * The assumption here is that the netbuf
+ * is arranged in the sockaddr_in
+ * style for IP cases.
+ */
+ u_short port;
+ struct sockaddr_in *sa;
+ struct netbuf remote;
+ int protocol;
+ char buf[32];
+ char *res;
+
+ clnt_control(client, CLGET_SVC_ADDR, (char *) &remote);
+ sa = (struct sockaddr_in *)(remote.buf);
+ protocol = strcmp(nc->nc_proto, NC_TCP) ?
+ IPPROTO_UDP : IPPROTO_TCP;
+ port = (u_short) pmap_getport(sa, prog, ver, protocol);
+
+ if (port != 0) {
+ /* print s_addr (and port) in host byte order */
+ sa->sin_addr.s_addr = ntohl(sa->sin_addr.s_addr);
+ sprintf(buf, "%d.%d.%d.%d.%d.%d",
+ (sa->sin_addr.s_addr >> 24) & 0xff,
+ (sa->sin_addr.s_addr >> 16) & 0xff,
+ (sa->sin_addr.s_addr >> 8) & 0xff,
+ (sa->sin_addr.s_addr) & 0xff,
+ (port >> 8) & 0xff,
+ port & 0xff);
+ res = strdup(buf);
+ if (res != 0) {
+ rpc_createerr.cf_stat = RPC_SUCCESS;
+ } else {
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ }
+ } else {
+ rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+ res = NULL;
+ }
+ clnt_destroy(client);
+ t_close(fd);
+ return (res);
+ }
+ clnt_destroy(client);
+ t_close(fd);
+ return (NULL);
+}
+
+#define bcmp(s1, s2, len) memcmp(s1, s2, len)
+#define bcopy(s1, s2, len) memcpy(s2, s1, len)
+
+#define MAXALIASES 35
+
+static char line[BUFSIZ+1];
+static char hostaddr[sizeof (struct in6_addr)];
+static struct hostent host;
+static char *host_aliases[MAXALIASES];
+static char *host_addrs[] = {
+ hostaddr,
+ NULL
+};
+
+static char *_hosts6[] = { "/etc/inet/ipnodes", 0 };
+static char *_hosts4[] = { "/etc/inet/ipnodes", "/etc/hosts", 0 };
+
+static char *any();
+
+static struct hostent *__files_gethostent();
+
+struct hostent *
+__files_gethostbyname(char *nam, char *fmly)
+{
+ register struct hostent *hp;
+ register char **cp;
+ char **file;
+ FILE *hostf;
+ sa_family_t af;
+
+ if (strcmp(fmly, NC_INET) == 0) {
+ af = AF_INET;
+ file = _hosts4;
+ } else if (strcmp(fmly, NC_INET6) == 0) {
+ af = AF_INET6;
+ file = _hosts6;
+ } else {
+ return (0);
+ }
+
+ for (; *file != 0; file++) {
+
+ if ((hostf = fopen(*file, "r")) == 0)
+ continue;
+
+ while (hp = __files_gethostent(hostf)) {
+ if (hp->h_addrtype != af)
+ continue;
+ if (strcasecmp(hp->h_name, nam) == 0) {
+ (void) fclose(hostf);
+ return (hp);
+ }
+ for (cp = hp->h_aliases; cp != 0 && *cp != 0; cp++)
+ if (strcasecmp(*cp, nam) == 0) {
+ (void) fclose(hostf);
+ return (hp);
+ }
+ }
+
+ (void) fclose(hostf);
+ }
+
+ return (0);
+}
+
+#define isV6Addr(s) (strchr(s, (int)':') != 0)
+
+static struct hostent *
+__files_gethostent(FILE *hostf)
+{
+ char *p;
+ register char *cp, **q;
+ struct in6_addr in6;
+ struct in_addr in4;
+ void *addr;
+ sa_family_t af;
+ int len;
+
+ if (hostf == NULL)
+ return (NULL);
+again:
+ if ((p = fgets(line, BUFSIZ, hostf)) == NULL)
+ return (NULL);
+ if (*p == '#')
+ goto again;
+ cp = any(p, "#\n");
+ if (cp == NULL)
+ goto again;
+ *cp = '\0';
+ cp = any(p, " \t");
+ if (cp == NULL)
+ goto again;
+ *cp++ = '\0';
+ /* THIS STUFF IS INTERNET SPECIFIC */
+ host.h_addr_list = host_addrs;
+ if (isV6Addr(p)) {
+ af = AF_INET6;
+ addr = (void *)&in6;
+ len = sizeof (in6);
+ } else {
+ af = AF_INET;
+ addr = (void *)&in4;
+ len = sizeof (in4);
+ }
+ if (inet_pton(af, p, addr) != 1)
+ goto again;
+ bcopy(addr, host.h_addr_list[0], len);
+ host.h_length = len;
+ host.h_addrtype = af;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ host.h_name = cp;
+ q = host.h_aliases = host_aliases;
+ cp = any(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &host_aliases[MAXALIASES - 1])
+ *q++ = cp;
+ cp = any(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ *q = NULL;
+ return (&host);
+}
+
+static char *
+any(cp, match)
+ register char *cp;
+ char *match;
+{
+ register char *mp, c;
+
+ while (c = *cp) {
+ for (mp = match; *mp; mp++)
+ if (*mp == c)
+ return (cp);
+ cp++;
+ }
+ return ((char *)0);
+}
diff --git a/usr/src/cmd/ypcmd/server.xml b/usr/src/cmd/ypcmd/server.xml
new file mode 100644
index 0000000000..e0baf7a0fa
--- /dev/null
+++ b/usr/src/cmd/ypcmd/server.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWypr:ypserver'>
+
+<service
+ name='network/nis/server'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <dependency
+ name='fs'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='rpcbind'
+ grouping='require_all'
+ restart_on='restart'
+ type='service'>
+ <service_fmri value='svc:/network/rpc/bind' />
+ </dependency>
+
+ <dependency
+ name='domain'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/identity:domain' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/yp'
+ timeout_seconds='300' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='60' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ NIS (YP) server
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='ypserv' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/ypcmd/shared/ancil.c b/usr/src/cmd/ypcmd/shared/ancil.c
new file mode 100644
index 0000000000..bd09a03a70
--- /dev/null
+++ b/usr/src/cmd/ypcmd/shared/ancil.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <dirent.h>
+#include "../ypsym.h"
+#include "../ypdefs.h"
+USE_YPDBPATH
+USE_DBM
+
+bool onmaplist();
+extern unsigned int strlen();
+extern int strcmp();
+extern int isvar_sysv();
+extern char *strncpy();
+
+/*
+ * This checks to see whether a domain name is present at the local node as a
+ * subdirectory of ypdbpath
+ */
+bool
+ypcheck_domain(domain)
+ char *domain;
+{
+ char path[MAXNAMLEN + 1];
+ struct stat filestat;
+ bool present = FALSE;
+
+ strcpy(path, ypdbpath);
+ strcat(path, "/");
+ strcat(path, domain);
+
+ if (stat(path, &filestat) != -1) {
+ if ((filestat.st_mode & S_IFDIR))
+ present = TRUE;
+ }
+ return (present);
+}
+
+/*
+ * This returns TRUE if map is on list, and FALSE otherwise.
+ */
+bool
+onmaplist(map, list)
+ char *map;
+ struct ypmaplist *list;
+{
+ struct ypmaplist *scan;
+
+ for (scan = list; scan; scan = scan->ypml_next) {
+
+ if (strcmp(map, scan->ypml_name) == 0) {
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
diff --git a/usr/src/cmd/ypcmd/shared/lockmap.c b/usr/src/cmd/ypcmd/shared/lockmap.c
new file mode 100644
index 0000000000..209ecad5a1
--- /dev/null
+++ b/usr/src/cmd/ypcmd/shared/lockmap.c
@@ -0,0 +1,359 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/mman.h>
+#include <thread.h>
+#include <synch.h>
+#include <ndbm.h>
+#include "../ypsym.h"
+#include "../ypdefs.h"
+
+/*
+ * These routines provide mutual exclusion between ypserv and ypxfr.
+ * Mutual exclusion is needed so that ypxfr doesn't try to rename
+ * dbm files while ypserv is trying to open them. After ypserv has
+ * opened a dbm file, it is safe to rename it because ypserv still
+ * has access to the file through its file descriptor.
+ */
+
+#define LOCKFILE "/var/run/yp_maplock"
+struct lockarray {
+ mutex_t locknode[MAXHASH];
+};
+typedef struct lockarray lockarray;
+
+/*
+ * Cross-process robust mutex locks.
+ * Provide synchronization between YP processes
+ * by implementing an exclusive locking mechanism
+ * via a memory-mapped file.
+ */
+static struct lockarray *shmlockarray;
+static int lockfile;
+
+int
+hash(char *s)
+{
+ int n = 0;
+ int i;
+
+ for (i = 1; *s; i += 10, s++) {
+ n += i * (*s);
+ }
+ n %= MAXHASH;
+ return (n);
+}
+
+bool
+init_locks_mem()
+{
+ int iiter, rc;
+ int ebusy_cnt = 0;
+
+ /*
+ * Initialize cross-process locks in memory-mapped file.
+ */
+ for (iiter = 0; iiter < MAXHASH; iiter++) {
+ if (rc = mutex_init(&(shmlockarray->locknode[iiter]),
+ USYNC_PROCESS_ROBUST, 0)) {
+ if (rc == EBUSY) {
+ ebusy_cnt++;
+ } else {
+ syslog(LOG_ERR,
+ "init_locks_mem():mutex_init():error=%d",
+ rc);
+ return (FALSE);
+ }
+ }
+ }
+
+ /*
+ * EBUSY for all locks OK, it means another process
+ * has already initialized locks.
+ */
+ if ((ebusy_cnt > 0) && (ebusy_cnt != MAXHASH)) {
+ syslog(LOG_ERR,
+ "%s inconsistent. Remove and restart NIS (YP).", LOCKFILE);
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool
+init_lock_map()
+{
+ char buff[ sizeof (lockarray) ];
+ int write_cnt, lf_size;
+ struct stat fdata;
+
+ /*
+ * Locking file initialization algorithm, with recovery mechanism.
+ * This mechanism has been devised to ensure proper creation
+ * of a memory-mapped lock file containing mutexes for robust,
+ * inter-process communication.
+ * File name is /var/run/yp_maplock (LOCKFILE). It might or might
+ * not exist.
+ *
+ * Algorithm:
+ * Try to open the file. If file doesn't exist, or size is too small,
+ * create/rewrite the file, m-map it into memory and initialize the
+ * mutexes in it.
+ * If file exists and size is at least large enough, assume it's a
+ * good file, and m-map the lock structure directly to it.
+ *
+ * Recovery from inconsistent state is easy - simply delete the file
+ * and restart NIS (YP).
+ */
+
+ lockfile = open(LOCKFILE, O_RDWR|O_CREAT, 0600);
+ if (lockfile != -1) {
+ if (lockf(lockfile, F_LOCK, 0) == 0) {
+ if (fstat(lockfile, &fdata) == 0) {
+ lf_size = fdata.st_size;
+ if (lf_size < sizeof (lockarray)) {
+ bzero(buff, sizeof (buff));
+ if ((write_cnt = write(lockfile, buff,
+ sizeof (buff)) != sizeof (buff))) {
+ if (write_cnt < 0) {
+ syslog(LOG_ERR,
+ "write(%s) => errno=%d",
+ LOCKFILE, errno);
+ } else {
+ syslog(LOG_ERR,
+ "write(%s) => %d!=%d: wrong number of bytes written.",
+ LOCKFILE,
+ write_cnt,
+ sizeof (buff));
+ }
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ return (FALSE);
+ }
+ }
+ } else {
+ syslog(LOG_ERR,
+ "fstat(%s) => errno=%d", LOCKFILE, errno);
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ return (FALSE);
+ }
+ } else {
+ syslog(LOG_ERR,
+ "lockf(%s,F_LOCK) => errno=%d", LOCKFILE, errno);
+ close(lockfile);
+ return (FALSE);
+ }
+ } else {
+ syslog(LOG_ERR,
+ "open(%s) => errno=%d", LOCKFILE, errno);
+ return (FALSE);
+ }
+
+ /*
+ * File exists with correct size, is open, and we're holding
+ * the file lock.
+ */
+ shmlockarray = (lockarray *)mmap((caddr_t) 0, sizeof (lockarray),
+ PROT_READ | PROT_WRITE, MAP_SHARED, lockfile, 0);
+ if (shmlockarray == MAP_FAILED) {
+ syslog(LOG_ERR, "mmap(%s) => errno=%d", LOCKFILE, errno);
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ return (FALSE);
+ }
+
+ /*
+ * If we wrote zeroes to the file, we also need to initialize
+ * the mutex locks.
+ */
+ if (lf_size < sizeof (lockarray)) {
+ if (init_locks_mem() == FALSE) {
+ lockf(lockfile, F_ULOCK, 0);
+ close(lockfile);
+ if (remove(LOCKFILE) != 0) {
+ syslog(LOG_ERR,
+ "remove(%s) => errno=%d: Please delete file.",
+ LOCKFILE, errno);
+ }
+ return (FALSE);
+ }
+ }
+
+ if (lockf(lockfile, F_ULOCK, 0) != 0) {
+ syslog(LOG_ERR,
+ "lockf(%s,F_ULOCK) => errno=%d",
+ LOCKFILE, errno);
+ close(lockfile);
+ return (FALSE);
+ }
+
+ if (close(lockfile) == 0) {
+ return (TRUE);
+ } else {
+ syslog(LOG_ERR,
+ "close(%s) => errno=%d", LOCKFILE, errno);
+ return (FALSE);
+ }
+}
+
+/*
+ * FUNCTION : lock_map()
+ *
+ * DESCRIPTION: Front end to the lock routine taking map name as argument.
+ *
+ * GIVEN : Map name.
+ *
+ * RETURNS : Same as lock_core
+ */
+int
+lock_map(char *mapname)
+{
+ int hashval;
+
+ hashval = hash(mapname);
+
+ return( lock_core(hashval));
+}
+
+/*
+ * FUNCTION : lock_core()
+ *
+ * DESCRIPTION: The core map locking function
+ *
+ * GIVEN : Map hash value
+ *
+ * RETURNS : 0 = Failure
+ * 1 = Success
+ */
+int
+lock_core(int hashval)
+{
+ int rc;
+
+ /*
+ *Robust, cross-process lock implementation
+ */
+ rc = mutex_lock(&(shmlockarray->locknode[hashval]));
+ while (rc != 0) {
+ switch (rc) {
+ case EOWNERDEAD:
+ /*
+ * Previows lock owner died, resetting lock
+ * to recover from error.
+ */
+ rc = mutex_init(&(shmlockarray->locknode[hashval]),
+ USYNC_PROCESS_ROBUST, 0);
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "mutex_init(): error=%d", rc);
+ return (0);
+ }
+ rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "mutex_unlock(): error=%d", rc);
+ return (0);
+ }
+ break;
+ default:
+ /*
+ * Unrecoverable problem - nothing to do
+ * but exit YP and delete lock file.
+ */
+ syslog(LOG_ERR,
+ "mutex_lock(): error=%d", rc);
+ syslog(LOG_ERR,
+ "Please restart NIS (ypstop/ypstart).");
+ if (remove(LOCKFILE) != 0) {
+ syslog(LOG_ERR,
+ "remove(%s) => errno=%d: Please delete file.",
+ LOCKFILE, errno);
+ }
+ return (0);
+ }
+ rc = mutex_lock(&(shmlockarray->locknode[hashval]));
+ }
+
+ /* Success */
+ return (1);
+}
+
+
+/*
+ * FUNCTION : unlock_map()
+ *
+ * DESCRIPTION: Front end to the unlock routine taking map name as argument.
+ *
+ * GIVEN : Map name.
+ *
+ * RETURNS : Same as unlock_core
+ */
+int
+unlock_map(char *mapname)
+{
+ int hashval;
+
+ hashval = hash(mapname);
+
+ return( unlock_core( hashval ));
+}
+
+/*
+ * FUNCTION : unlock_core()
+ *
+ * DESCRIPTION: The core map locking function
+ *
+ * GIVEN : Map hash value
+ *
+ * RETURNS : 0 = Failure
+ * 1 = Success
+ */
+int
+unlock_core(int hashval)
+{
+ int rc;
+
+ rc = mutex_unlock(&(shmlockarray->locknode[hashval]));
+ if (rc != 0) {
+ syslog(LOG_ERR,
+ "mutex_unlock(): error=%d", rc);
+ syslog(LOG_ERR,
+ "Please restart NIS (ypstop/ypstart).");
+ if (remove(LOCKFILE) != 0) {
+ syslog(LOG_ERR,
+ "remove(%s) => errno=%d: Please delete file.",
+ LOCKFILE, errno);
+ }
+ return (0);
+ }
+
+ /* Success */
+ return (1);
+}
diff --git a/usr/src/cmd/ypcmd/shared/utils.c b/usr/src/cmd/ypcmd/shared/utils.c
new file mode 100644
index 0000000000..f8632cb34e
--- /dev/null
+++ b/usr/src/cmd/ypcmd/shared/utils.c
@@ -0,0 +1,344 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * DESCRIPTION: This file contains various functions used by more than one NIS
+ * components. A lot of this code started off in ypxfr and then
+ * got used by other components. Some of it has become a little
+ * 'quirky' and should probably be re-worked.
+ */
+
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/mman.h>
+#include <thread.h>
+#include <synch.h>
+#include <stdarg.h>
+#include <ndbm.h>
+#include "../ypsym.h"
+#include "../ypdefs.h"
+#include "shim.h"
+
+USE_DBM
+
+/*
+ * Globals
+ */
+
+/*
+ * DESCRIPTION : Utility functions used by everything.
+ */
+bool check_map_existence(char *);
+void logprintf2(char *format, ...);
+
+/*
+ * This checks to see if the source map files exist, then renames them to the
+ * target names. This is a boolean function. The file names from.pag and
+ * from.dir will be changed to to.pag and to.dir in the success case.
+ *
+ * Note: If the second of the two renames fails, yprename_map will try to
+ * un-rename the first pair, and leave the world in the state it was on entry.
+ * This might fail, too, though...
+ *
+ * GIVEN : Name of map to copy from
+ * Name of map to copy to
+ * Flag indicating if map is secure.
+ */
+bool
+rename_map(from, to, secure_map)
+ char *from;
+ char *to;
+ bool_t secure_map;
+{
+ char fromfile[MAXNAMLEN + 1];
+ char tofile[MAXNAMLEN + 1];
+ char savefile[MAXNAMLEN + 1];
+
+ if (!from || !to) {
+ return (FALSE);
+ }
+
+ if (!check_map_existence(from)) {
+ return (FALSE);
+ }
+
+ (void) strcpy(fromfile, from);
+ (void) strcat(fromfile, dbm_pag);
+ (void) strcpy(tofile, to);
+ (void) strcat(tofile, dbm_pag);
+
+ if (rename(fromfile, tofile)) {
+ logprintf2("Can't mv %s to %s.\n", fromfile,
+ tofile);
+ return (FALSE);
+ }
+
+ (void) strcpy(savefile, tofile);
+ (void) strcpy(fromfile, from);
+ (void) strcat(fromfile, dbm_dir);
+ (void) strcpy(tofile, to);
+ (void) strcat(tofile, dbm_dir);
+
+ if (rename(fromfile, tofile)) {
+ logprintf2("Can't mv %s to %s.\n", fromfile,
+ tofile);
+ (void) strcpy(fromfile, from);
+ (void) strcat(fromfile, dbm_pag);
+ (void) strcpy(tofile, to);
+ (void) strcat(tofile, dbm_pag);
+
+ if (rename(tofile, fromfile)) {
+ logprintf2(
+ "Can't recover from rename failure.\n");
+ return (FALSE);
+ }
+
+ return (FALSE);
+ }
+
+ if (!secure_map) {
+ chmod(savefile, 0644);
+ chmod(tofile, 0644);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Function : delete_map()
+ *
+ * Description: Deletes a map
+ *
+ * Given : Map name
+ *
+ * Return : TRUE = Map deleted
+ * FALSE = Map not completly deleted
+ */
+bool
+delete_map(name)
+ char *name;
+{
+ char fromfile[MAXNAMLEN + 1];
+
+ if (!name) {
+ return (FALSE);
+ }
+
+ if (!check_map_existence(name)) {
+ /* Already gone */
+ return (TRUE);
+ }
+
+ (void) strcpy(fromfile, name);
+ (void) strcat(fromfile, dbm_pag);
+
+ if (unlink(fromfile)) {
+ logprintf2("Can't unlink %s.\n", fromfile);
+ return (FALSE);
+ }
+
+ (void) strcpy(fromfile, name);
+ (void) strcat(fromfile, dbm_dir);
+
+ if (unlink(fromfile)) {
+ logprintf2("Can't unlink %s.\n", fromfile);
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * This performs an existence check on the dbm data base files <pname>.pag and
+ * <pname>.dir.
+ */
+bool
+check_map_existence(pname)
+ char *pname;
+{
+ char dbfile[MAXNAMLEN + 1];
+ struct stat filestat;
+ int len;
+
+ if (!pname || ((len = strlen(pname)) == 0) ||
+ (len + 5) > (MAXNAMLEN + 1)) {
+ return (FALSE);
+ }
+
+ errno = 0;
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, dbm_dir);
+
+ if (stat(dbfile, &filestat) != -1) {
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, dbm_pag);
+
+ if (stat(dbfile, &filestat) != -1) {
+ return (TRUE);
+ } else {
+
+ if (errno != ENOENT) {
+ logprintf2(
+ "Stat error on map file %s.\n",
+ dbfile);
+ }
+
+ return (FALSE);
+ }
+
+ } else {
+
+ if (errno != ENOENT) {
+ logprintf2(
+ "Stat error on map file %s.\n",
+ dbfile);
+ }
+
+ return (FALSE);
+ }
+}
+
+/*
+ * FUNCTION : logprintf2()
+ *
+ * DESCRIPTION: The functions in this file were oringinaly shared between
+ * ypxfr and ypserv. On error they called logprintf().
+ * Unfortunatly this had been implemented differently in the two
+ * sources and not at all in some of the NIS components required
+ * for N2L.
+ *
+ * This function is simplified version of logprinf() as/when
+ * possible the other error calls should be migrated to use this
+ * common version. If a common set of functionality can be found
+ * this versions should be modified to support it.
+ */
+void
+logprintf2(char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ syslog(LOG_ERR, format, ap);
+
+ va_end(ap);
+}
+
+/*
+ * This performs an existence check on the dbm data base files <name>.pag and
+ * <name>.dir. pname is a ptr to the filename. This should be an absolute
+ * path.
+ * Returns TRUE if the map exists and is accessable; else FALSE.
+ *
+ * Note: The file name should be a "base" form, without a file "extension" of
+ * .dir or .pag appended. See ypmkfilename for a function which will generate
+ * the name correctly. Errors in the stat call will be reported at this level,
+ * however, the non-existence of a file is not considered an error, and so will
+ * not be reported.
+ */
+bool
+ypcheck_map_existence(char *pname)
+{
+ char dbfile[MAXNAMLEN + sizeof (TTL_POSTFIX) + 1];
+ struct stat filestat;
+ int len;
+
+ if (!pname || ((len = (int)strlen(pname)) == 0) ||
+ (len + sizeof (dbm_pag)) > (MAXNAMLEN + 1)) {
+ return (FALSE);
+ }
+
+ errno = 0;
+
+ /* Check for existance of .dir file */
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, dbm_dir);
+
+ if (stat(dbfile, &filestat) == -1) {
+ if (errno != ENOENT) {
+ (void) fprintf(stderr,
+ "ypserv: Stat error on map file %s.\n",
+ dbfile);
+ }
+ return (FALSE);
+ }
+
+ /* Check for existance of .pag file */
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, dbm_pag);
+
+ if (stat(dbfile, &filestat) == -1) {
+ if (errno != ENOENT) {
+ (void) fprintf(stderr,
+ "ypserv: Stat error on map file %s.\n",
+ dbfile);
+ }
+ return (FALSE);
+ }
+
+ if (yptol_mode) {
+ /* Check for existance of TTL .dir file */
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, TTL_POSTFIX);
+ (void) strcat(dbfile, dbm_dir);
+
+ if (stat(dbfile, &filestat) == -1) {
+ if (errno != ENOENT) {
+ (void) fprintf(stderr,
+ "ypserv: Stat error on map file %s.\n",
+ dbfile);
+ }
+ return (FALSE);
+ }
+
+ /* Check for existance of TTL .pag file */
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, TTL_POSTFIX);
+ (void) strcat(dbfile, dbm_pag);
+
+ if (stat(dbfile, &filestat) == -1) {
+ if (errno != ENOENT) {
+ (void) fprintf(stderr,
+ "ypserv: Stat error on map file %s.\n",
+ dbfile);
+ }
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
diff --git a/usr/src/cmd/ypcmd/stdethers.c b/usr/src/cmd/ypcmd/stdethers.c
new file mode 100644
index 0000000000..36771125af
--- /dev/null
+++ b/usr/src/cmd/ypcmd/stdethers.c
@@ -0,0 +1,77 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1987-1990,2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/ethernet.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <strings.h>
+
+/*
+ * Filter to convert addresses in /etc/ethers file to standard form
+ */
+
+int
+main(int argc, char **argv)
+{
+ /*
+ * The hostname buffer must be at least as large as the line buffer
+ * to avoid buffer overflows when ether_line(3SOCKET) is called.
+ * We simply use the same size for both buffers to be safe.
+ */
+ char line[MAXHOSTNAMELEN + 256], *lf, hostname[sizeof (line)];
+ struct ether_addr e;
+ FILE *in;
+
+ if (argc > 1) {
+ in = fopen(argv[1], "r");
+ if (in == NULL) {
+ fprintf(stderr,
+ "%s: can't open %s\n", argv[0], argv[1]);
+ return (1);
+ }
+ } else {
+ in = stdin;
+ }
+ while (fgets(line, sizeof (line), in) != NULL) {
+ lf = strchr(line, '\n');
+ if (lf != NULL)
+ *lf = '\0';
+ if ((line[0] == '#') || (line[0] == '\0'))
+ continue;
+ if (ether_line(line, &e, hostname) == 0) {
+ (void) fprintf(stdout, "%s\t%s\n", ether_ntoa(&e),
+ hostname);
+ } else {
+ (void) fprintf(stderr,
+ "%s: ignoring line: %s\n", argv[0], line);
+ }
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/ypcmd/stdhosts.c b/usr/src/cmd/ypcmd/stdhosts.c
new file mode 100644
index 0000000000..ec5260b4ca
--- /dev/null
+++ b/usr/src/cmd/ypcmd/stdhosts.c
@@ -0,0 +1,335 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1985-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SMI4.1 1.7 */
+
+#include <stdio.h>
+#include <ndbm.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+/*
+ * Filter to convert both IPv4 and IPv6 addresses from /etc/hosts or
+ * /etc/inet/ipnodes files.
+ */
+
+/*
+ * Size of buffer for input lines. Add two bytes on input for newline
+ * and terminating NULL. Note that the practical limit for data
+ * storage in ndbm is (PBLKSIZ - 3 * sizeof (short)). Though this
+ * differs from spec 1170 the common industry implementation does
+ * conform to this slightly lower limit.
+ */
+
+#define OUTPUTSIZ (PBLKSIZ - 3 * sizeof (short))
+#define INPUTSIZ (OUTPUTSIZ + 2)
+
+static int ipv4 = -1;
+static char *cmd;
+int warn = 0;
+
+static void verify_and_output(const char *key, char *value, int lineno);
+
+void
+usage()
+{
+ fprintf(stderr, "stdhosts [-w] [-n] [in-file]\n");
+ fprintf(stderr, "\t-w\tprint malformed warning messages.\n");
+ exit(1);
+}
+
+main(argc, argv)
+ char **argv;
+{
+ char line[INPUTSIZ];
+ char adr[INPUTSIZ];
+ char nadr[INET6_ADDRSTRLEN]; /* Contains normalised address */
+ const char *nadrp; /* Pointer to the normalised address */
+ char *trailer;
+ char *commentp; /* Pointer to comment character '#' */
+ int c;
+ FILE *fp;
+ int lineno = 0; /* Input line counter */
+ struct in_addr in; /* Used for normalising the IPv4 address */
+ struct in6_addr in6; /* Used for normalising the IPv6 address */
+ char *fgetsp; /* Holds return value for fgets() calls */
+ int endoffile = 0; /* Set when end of file reached */
+
+ if (cmd = strrchr(argv[0], '/'))
+ ++cmd;
+ else
+ cmd = argv[0];
+
+ while ((c = getopt(argc, argv, "v:wn")) != -1) {
+ switch (c) {
+ case 'w': /* Send warning messages to stderr */
+ warn = 1;
+ break;
+ case 'n':
+ ipv4 = 0;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ if (optind < argc) {
+ fp = fopen(argv[optind], "r");
+ if (fp == NULL) {
+ fprintf(stderr, "%s: can't open %s\n",
+ cmd, argv[optind]);
+ exit(1);
+ }
+ } else
+ fp = stdin;
+
+ while (!endoffile &&
+ (fgetsp = fgets(line, sizeof (line), fp)) != NULL) {
+ lineno++;
+
+ /* Check for comments */
+ if ((commentp = strchr(line, '#')) != NULL) {
+ if ((line[strlen(line) - 1] != '\n') &&
+ (strlen(line) >= (sizeof (line) - 1))) {
+ /*
+ * Discard the remainder of the line
+ * until the newline or EOF, then
+ * continue to parse the line. Use
+ * adr[] rather then line[] to
+ * preserve the contents of line[].
+ */
+ while ((fgetsp = fgets(adr, sizeof (adr),
+ fp)) != NULL) {
+ if (adr[strlen(adr) - 1] == '\n')
+ break;
+ }
+ if (fgetsp == NULL)
+ endoffile = 1;
+ }
+ /* Terminate line[] at the comment character */
+ *commentp = '\0';
+ } else if ((line[strlen(line) - 1] != '\n') &&
+ (strlen(line) >= (sizeof (line) - 1))) {
+ /*
+ * Catch long lines but not if this is a short
+ * line with no '\n' at the end of the input.
+ */
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: more than %d "
+ "bytes on line %d, ignored\n",
+ cmd, sizeof (line) - 2, lineno);
+ /*
+ * Discard the remaining lines until the
+ * newline or EOF.
+ */
+ while ((fgetsp = fgets(line, sizeof (line),
+ fp)) != NULL)
+ if (line[strlen(line) - 1] == '\n')
+ break;
+ if (fgetsp == NULL)
+ endoffile = 1;
+ continue;
+ }
+
+ if (sscanf(line, "%s", adr) != 1) { /* Blank line, ignore */
+ continue;
+ }
+
+ if ((trailer = strpbrk(line, " \t")) == NULL) {
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: no host names on line %d, "
+ "ignored\n", cmd, lineno);
+ continue;
+ }
+
+ /*
+ * check for valid addresses
+ *
+ * Attempt an ipv4 conversion, this accepts all valid
+ * ipv4 addresses including:
+ * d
+ * d.d
+ * d.d.d
+ * Unfortunately inet_pton() doesn't recognise these.
+ */
+
+ in.s_addr = inet_addr(adr);
+ if (-1 != (int)in.s_addr) {
+ /*
+ * It's safe not to check return of NULL as
+ * nadrp is checked for validity later.
+ */
+ nadrp = inet_ntop(AF_INET, &in, nadr, sizeof (nadr));
+ } else {
+ nadrp = NULL; /* Not a valid IPv4 address */
+ }
+
+ if (ipv4) {
+ if (nadrp == NULL) {
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: malformed address on"
+ " line %d, ignored\n",
+ cmd, lineno);
+ continue;
+ }
+ } else { /* v4 or v6 for ipnodes */
+ if (nadrp == NULL) {
+ if (inet_pton(AF_INET6, adr, &in6) == 1) {
+ nadrp = inet_ntop(AF_INET6, &in6,
+ nadr, sizeof (nadr));
+ }
+ if (nadrp == NULL) { /* Invalid IPv6 too */
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: malformed"
+ " address on"
+ " line %d, ignored\n",
+ cmd, lineno);
+ continue;
+ }
+ }
+ }
+
+ verify_and_output(nadrp, trailer, lineno);
+
+ } /* while */
+ exit(0);
+ /* NOTREACHED */
+}
+
+/*
+ * verify_and_output
+ *
+ * Builds and verifies the output key and value string
+ *
+ * It makes sure these rules are followed:
+ * key + separator + value <= OUTPUTSIZ (for ndbm)
+ * names <= MAXALIASES + 1, ie one canonical name + MAXALIASES aliases
+ * It will also ignore everything after a '#' comment character
+ */
+static void
+verify_and_output(const char *key, char *value, int lineno)
+{
+ char *p; /* General char pointer */
+ char *endp; /* Points to the NULL at the end */
+ char *namep; /* First character of a name */
+ char tmpbuf[OUTPUTSIZ+1]; /* Buffer before writing out */
+ char *tmpbufp = tmpbuf; /* Current point in output string */
+ int n = 0; /* Length of output */
+ int names = 0; /* Number of names found */
+ int namelen; /* Length of the name */
+
+ if (key) { /* Just in case key is NULL */
+ n = strlen(key);
+ if (n > OUTPUTSIZ) {
+ if (warn)
+ fprintf(stderr,
+ "%s: address too long on "
+ "line %d, line discarded\n",
+ cmd, lineno);
+ return;
+ }
+ memcpy(tmpbufp, key, n+1); /* Plus the '\0' */
+ tmpbufp += n;
+ }
+
+ if (value) { /* Just in case value is NULL */
+ p = value;
+ if ((endp = strchr(value, '#')) == 0) /* Ignore # comments */
+ endp = p + strlen(p); /* Or endp = EOL */
+ do {
+ /*
+ * Skip white space. Type conversion is
+ * necessary to avoid unfortunate effects of
+ * 8-bit characters appearing negative.
+ */
+ while ((p < endp) && isspace((unsigned char)*p))
+ p++;
+
+ if (p == endp) /* End of the string */
+ break;
+
+ names++;
+ if (names > (MAXALIASES+1)) { /* cname + MAXALIASES */
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: too many "
+ "host names on line %d, "
+ "truncating\n",
+ cmd, lineno);
+ break;
+ }
+
+ namep = p;
+ while ((p < endp) && !isspace((unsigned char)*p))
+ p++;
+
+ namelen = p - namep;
+ n += namelen + 1; /* single white space + name */
+ *p = '\0'; /* Terminate the name string */
+ if (n > OUTPUTSIZ) {
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: %d byte ndbm limit "
+ "reached on line %d, truncating\n",
+ cmd, OUTPUTSIZ, lineno);
+ break;
+ }
+
+ if (names == 1) /* First space is a '\t' */
+ *tmpbufp++ = '\t';
+ else
+ *tmpbufp++ = ' ';
+
+ memcpy(tmpbufp, namep, namelen+1); /* Plus the '\0' */
+ tmpbufp += namelen;
+
+ if (p < endp)
+ p++; /* Skip the added NULL */
+
+ } while (p < endp);
+ }
+
+ if (names > 0) {
+ fputs(tmpbuf, stdout);
+ fputc('\n', stdout);
+ } else {
+ if (warn)
+ fprintf(stderr,
+ "%s: Warning: no host names on line %d, "
+ "ignored\n", cmd, lineno);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/udpublickey.c b/usr/src/cmd/ypcmd/udpublickey.c
new file mode 100644
index 0000000000..2037f8270d
--- /dev/null
+++ b/usr/src/cmd/ypcmd/udpublickey.c
@@ -0,0 +1,188 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1992 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * YP updater for public key map
+ */
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <sys/file.h>
+
+extern char *malloc();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ unsigned op;
+ char name[MAXNETNAMELEN + 1];
+ char key[256];
+ char data[256];
+ char line[256];
+ unsigned keylen;
+ unsigned datalen;
+ FILE *rf;
+ FILE *wf;
+ char *fname;
+ char *tmpname;
+ int err;
+
+
+ if (argc != 3) {
+ exit(YPERR_YPERR);
+ }
+ fname = argv[1];
+ tmpname = malloc(strlen(fname) + 4);
+ if (tmpname == NULL) {
+ exit(YPERR_YPERR);
+ }
+ sprintf(tmpname, "%s.tmp", fname);
+
+ /*
+ * Get input
+ */
+ if (! scanf("%s\n", name)) {
+ exit(YPERR_YPERR);
+ }
+ if (! scanf("%u\n", &op)) {
+ exit(YPERR_YPERR);
+ }
+ if (! scanf("%u\n", &keylen)) {
+ exit(YPERR_YPERR);
+ }
+ if (! fread(key, keylen, 1, stdin)) {
+ exit(YPERR_YPERR);
+ }
+ key[keylen] = 0;
+ if (! scanf("%u\n", &datalen)) {
+ exit(YPERR_YPERR);
+ }
+ if (! fread(data, datalen, 1, stdin)) {
+ exit(YPERR_YPERR);
+ }
+ data[datalen] = 0;
+
+ /*
+ * Check permission
+ */
+ if (strcmp(name, key) != 0) {
+ exit(YPERR_ACCESS);
+ }
+ if (strcmp(name, "nobody") == 0) {
+ /*
+ * Can't change "nobody"s key.
+ */
+ exit(YPERR_ACCESS);
+ }
+
+ /*
+ * Open files
+ */
+ rf = fopen(fname, "r");
+ if (rf == NULL) {
+ exit(YPERR_YPERR);
+ }
+ wf = fopen(tmpname, "w");
+ if (wf == NULL) {
+ exit(YPERR_YPERR);
+ }
+ err = -1;
+ while (fgets(line, sizeof (line), rf)) {
+ if (err < 0 && match(line, name)) {
+ switch (op) {
+ case YPOP_INSERT:
+ err = YPERR_KEY;
+ break;
+ case YPOP_STORE:
+ case YPOP_CHANGE:
+ fprintf(wf, "%s %s\n", key, data);
+ err = 0;
+ break;
+ case YPOP_DELETE:
+ /* do nothing */
+ err = 0;
+ break;
+ }
+ } else {
+ fputs(line, wf);
+ }
+ }
+ if (err < 0) {
+ switch (op) {
+ case YPOP_CHANGE:
+ case YPOP_DELETE:
+ err = YPERR_KEY;
+ break;
+ case YPOP_INSERT:
+ case YPOP_STORE:
+ err = 0;
+ fprintf(wf, "%s %s\n", key, data);
+ break;
+ }
+ }
+ fclose(wf);
+ fclose(rf);
+ if (err == 0) {
+ if (rename(tmpname, fname) < 0) {
+ exit(YPERR_YPERR);
+ }
+ } else {
+ if (unlink(tmpname) < 0) {
+ exit(YPERR_YPERR);
+ }
+ }
+ if (fork() == 0) {
+ close(0); close(1); close(2);
+ open("/dev/null", O_RDWR, 0);
+ dup(0); dup(0);
+ execl("/bin/sh", "sh", "-c", argv[2], NULL);
+ }
+ exit(err);
+ /* NOTREACHED */
+}
+
+
+match(line, name)
+ char *line;
+ char *name;
+{
+ int len;
+
+ len = strlen(name);
+ return (strncmp(line, name, len) == 0 &&
+ (line[len] == ' ' || line[len] == '\t'));
+}
diff --git a/usr/src/cmd/ypcmd/xfr.xml b/usr/src/cmd/ypcmd/xfr.xml
new file mode 100644
index 0000000000..805b64abb6
--- /dev/null
+++ b/usr/src/cmd/ypcmd/xfr.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWypr:xfr'>
+
+<service
+ name='network/nis/xfr'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <dependency
+ name='fs'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='rpcbind'
+ grouping='require_all'
+ restart_on='restart'
+ type='service'>
+ <service_fmri value='svc:/network/rpc/bind' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/lib/netsvc/yp/ypxfrd'
+ timeout_seconds='300' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='30' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ NIS (YP) transfer daemon
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='ypxfrd' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/ypcmd/yp.sh b/usr/src/cmd/ypcmd/yp.sh
new file mode 100644
index 0000000000..ba329f450d
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+. /lib/svc/share/smf_include.sh
+
+YPDIR=/usr/lib/netsvc/yp
+
+case $SMF_FMRI in
+ 'svc:/network/nis/client:default')
+ domain=`domainname`
+
+ if [ -z "$domain" ]; then
+ echo "$0: domainname not set"
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+
+ if [ ! -d /var/yp/binding/$domain ]; then
+ echo "$0: /var/yp/binding/$domain is not a directory"
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+
+ # Since two ypbinds will cause ypwhich to hang...
+ if pgrep -z `/sbin/zonename` ypbind >/dev/null; then
+ echo "$0: ypbind is already running."
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+
+ if [ -f /var/yp/binding/$domain/ypservers ]; then
+ $YPDIR/ypbind > /dev/null 2>&1
+ else
+ $YPDIR/ypbind -broadcast > /dev/null 2>&1
+ fi
+
+ rc=$?
+ if [ $rc != 0 ]; then
+ echo "$0: ypbind failed with $rc"
+ exit 1
+ fi
+ ;;
+
+ 'svc:/network/nis/server:default')
+ domain=`domainname`
+
+ if [ -z "$domain" ]; then
+ echo "$0: domainname not set"
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+
+ if [ ! -d /var/yp/$domain ]; then
+ echo "$0: domain directory missing"
+ exit $SMF_EXIT_ERR_CONFIG
+ fi
+
+ if [ -f /etc/resolv.conf ]; then
+ $YPDIR/ypserv -d
+ else
+ $YPDIR/ypserv
+ fi
+
+ rc=$?
+ if [ $rc != 0 ]; then
+ echo "$0: ypserv failed with $rc"
+ exit 1
+ fi
+ ;;
+
+ 'svc:/network/nis/passwd:default')
+ PWDIR=`grep "^PWDIR" /var/yp/Makefile 2> /dev/null` \
+ && PWDIR=`expr "$PWDIR" : '.*=[ ]*\([^ ]*\)'`
+ if [ "$PWDIR" ]; then
+ if [ "$PWDIR" = "/etc" ]; then
+ unset PWDIR
+ else
+ PWDIR="-D $PWDIR"
+ fi
+ fi
+ $YPDIR/rpc.yppasswdd $PWDIR -m
+
+ rc=$?
+ if [ $rc != 0 ]; then
+ echo "$0: rpc.yppasswdd failed with $rc"
+ exit 1
+ fi
+ ;;
+
+ *)
+ echo "$0: Unknown service \"$SMF_FMRI\"."
+ exit $SMF_EXIT_ERR_CONFIG
+ ;;
+esac
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/ypcmd/yp2lscripts/Makefile b/usr/src/cmd/ypcmd/yp2lscripts/Makefile
new file mode 100644
index 0000000000..664265d2e8
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp2lscripts/Makefile
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+OBJS= inityp2l ypmap2src
+
+include $(SRC)/cmd/Makefile.cmd
+
+# install directories
+NETSVC = $(ROOTLIB)/netsvc
+NETYP = $(NETSVC)/yp
+ROOTNETYPFILES= $(OBJS:%=$(NETYP)/%)
+
+$(NETSVC) := FILEMODE=555
+$(NETSVC) := OWNER=root
+$(NETSVC) := GROUP=bin
+
+all: FRC $(OBJS)
+
+install: all $(ROOTNETYPFILES)
+
+clean: FRC $(OBJS)
+ $(RM) $(OBJS)
+
+clobber: FRC $(OBJS)
+ $(RM) $(OBJS)
+
+clean: FRC
+
+clobber: FRC
+
+lint: FRC
+
+$(NETYP)/ypmap2src: ypmap2src
+ $(INS.file) ypmap2src
+
+$(NETYP)/inityp2l: inityp2l
+ $(INS.file) inityp2l
+
+FRC:
diff --git a/usr/src/cmd/ypcmd/yp2lscripts/inityp2l.sh b/usr/src/cmd/ypcmd/yp2lscripts/inityp2l.sh
new file mode 100644
index 0000000000..65209f7a92
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp2lscripts/inityp2l.sh
@@ -0,0 +1,5784 @@
+#! /usr/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# inityp2l -- Utility to generate YP (NIS) to LDAP
+# configuration file (/etc/default/ypserv)
+# and mapping file (/var/yp/NISLDAPmapping)
+#
+
+
+
+#
+# Displays message corresponding to the argument tag passed.
+#
+display_msg()
+{
+ case "$1" in
+ usage) cat <<EOF
+
+ $PROG: [ -m mapping_file ] [ -c config_file ]
+ m <mapping_file> Name of the generated NISLDAP mapping file
+ Default is /var/yp/NISLDAPmapping
+ c <config_file> Name of the generated ypserv configuration file
+ Default is /etc/default/ypserv
+
+EOF
+ ;;
+ no_config_file_name_specified) cat <<EOF
+
+You have not specified the config file name. You still have the
+option to skip creating this file, specify a config file name, or
+continue creating it with the default file name (${CONFIG_FILE}).
+
+EOF
+ ;;
+ no_mapping_file_name_specified) cat <<EOF
+
+You have not specified the mapping file name. You still have the
+option to skip creating this file, specify a mapping file name, or
+continue creating it with the default file name (${MAP_FILE}).
+
+EOF
+ ;;
+ new_config_file_name_help) cat <<EOF
+
+You can either specify a new file name, or accept the default
+config file name (${CONFIG_FILE}).
+
+It is recommended not to use the default file name since this
+script just helps with rapid creation of a config file. You
+should examine it's content before using it.
+
+EOF
+ ;;
+ new_mapping_file_name_help) cat <<EOF
+
+You can either specify a new file name, or accept the default
+mapping file name (${MAP_FILE}).
+
+It is recommended not to use the default file name since this
+script just helps with rapid creation of a mapping file. You
+should examine it's content before using it. And if there are
+custom maps, then their entries in the mapping file need to be
+customized too.
+
+Also, creation of default mapping file would cause NIS components
+to work in NIS to LDAP (N2L), rather than traditional NIS, mode
+when next restarted.
+
+EOF
+ ;;
+ backup_config_file) cat <<EOF
+
+The config file "${CONFIG_FILE}" already exists. It is strongly
+recommended that you BACKUP this file before running $PROG.
+
+However, even if you continue, you would be given the option to
+back up this file before it gets overwritten.
+
+EOF
+ ;;
+ backup_mapping_file) cat <<EOF
+
+The mapping file "${MAP_FILE}" already exists. It is strongly
+recommended that you BACKUP this file before running $PROG.
+
+However, even if you continue, you would be given the option to
+back up this file before it gets overwritten.
+
+EOF
+ ;;
+ warn_n2l_mode) cat <<EOF
+
+Warning : Creation of default mapping file (`basename $MAP_FILE`)
+ at default location (`dirname $MAP_FILE`) would cause NIS
+ components to work in NIS to LDAP (N2L) mode, rather than
+ traditional NIS mode, when next restarted.
+
+ "$PROG" assists with rapid creation of a simple N2L mapping
+ file. The user should examine it's content before using it.
+ For custom maps, this file needs to be customized which can
+ be done using standard text editors.
+
+EOF
+ ;;
+ config_auth_method_menu) cat <<EOF
+ The following are the supported Authentication Methods -
+ 1 none
+ 2 simple
+ 3 sasl/cram-md5
+ 4 sasl/digest-md5
+EOF
+ ;;
+ auth_method_menu) cat <<EOF
+ The following are the supported Authentication Methods -
+ 1 simple
+ 2 sasl/cram-md5
+ 3 sasl/digest-md5
+EOF
+ ;;
+ tls_method_menu) cat <<EOF
+ The following are the supported TLS Methods -
+ 1 none
+ 2 ssl
+EOF
+ ;;
+ retrieve_error_action_menu) cat <<EOF
+ The following are the supported actions -
+ 1 use_cached
+ 2 fail
+EOF
+ ;;
+ store_error_action_menu) cat <<EOF
+ The following are the supported actions -
+ 1 retry
+ 2 fail
+EOF
+ ;;
+ sorry) cat <<EOF
+
+HELP - No help is available for this topic.
+
+EOF
+ ;;
+ backup_config_file_cont_help) cat <<EOF
+
+HELP - Since $PROG will overwrite the existing config file, it is
+ strongly recommended that you backup this file prior to
+ running this utility.
+
+ However, even if you continue, you would be given the option
+ to back up this file before it gets overwritten.
+
+EOF
+ ;;
+ backup_config_file_help) cat <<EOF
+
+HELP - If you choose to backup the existing config file, it would be
+ saved with current date and time suffix in yymmdd.HH.MM.SS format.
+
+EOF
+ ;;
+ backup_mapping_file_cont_help) cat <<EOF
+
+HELP - Since $PROG will overwrite the existing mapping file, it is
+ strongly recommended that you backup this file prior to running
+ this utility.
+
+ However, even if you continue, you would be given the option to
+ back up this file before it gets overwritten.
+
+EOF
+ ;;
+ backup_mapping_file_help) cat <<EOF
+
+HELP - If you choose to backup the existing mapping file, it would be
+ saved with current date and time suffix in yymmdd.HH.MM.SS format.
+
+EOF
+ ;;
+ warn_n2l_mode_help) cat <<EOF
+
+HELP - It is strongly recommended that the mapping file is created at
+ non-default location (other than `dirname $MAP_FILE`). After this,
+ it's content should be verified, custom maps should be handled,
+ and if NIS components are desired to run in NIS to LDAP (N2L),
+ then only it should be copied at the default location.
+
+EOF
+ ;;
+ nisLDAPconfigDN_help) cat <<EOF
+
+HELP - The DN which stores the configuration information in LDAP.
+ There is no default value for this field. Leave empty or
+ undefined to get this information from config file (ypserv).
+
+EOF
+ ;;
+ nisLDAPconfigPreferredServerList_help) cat <<EOF
+
+HELP - List of directory servers to provide the configuration
+ information. There is no default. The preferred servers
+ must be entered IN THE ORDER you wish to have them contacted.
+ The preferred server list is a space separated list of IP
+ addresses. Providing port numbers is optional, and when not
+ supplied, port 389 is assumed. For an LDAP server running
+ on this machine, at port 389, use "127.0.0.1:389".
+
+EOF
+ ;;
+ auth_help) cat <<EOF
+
+HELP - The authentication method to be used to obtain information
+ from LDAP server. The supported methods are provided in menu.
+
+EOF
+ ;;
+ tls_help) cat <<EOF
+
+HELP - The transport layer security used for connection to the LDAP
+ server. In order to successfully use transport layer security,
+ the server must also support the chosen values. The supported
+ methods are provided in menu. Default is "$DEF_TLS".
+
+EOF
+ ;;
+ TLSCertificateDBPath_help) cat <<EOF
+
+HELP - The absolute path name of the file containing the certificate
+ database. The default value is "$DEF_TLSCertificateDBPath"
+
+EOF
+ ;;
+ nisLDAPconfigProxyUser_help) cat <<EOF
+
+HELP - The bind DN of the proxy user used to obtain configuration
+ information. There is no default value. If the value ends
+ with a comma, the value of the nisLDAPconfigDN attribute
+ is appended.
+
+EOF
+ ;;
+ ProxyPassword_warn) cat <<EOF
+
+Warning : In order to avoid having this password publicly visible
+ on the machine, the password should appear only in the
+ configuration file, and the file should have an appropriate
+ owner, group, and file mode.
+
+ So, once this file is ready, please modify appropriately
+ to make sure this file is well protected.
+
+EOF
+ ;;
+ preferredServerList_help) cat <<EOF
+
+HELP - List of directory servers for mapping data to/from LDAP.
+ There is no default. The preferred servers must be entered
+ IN THE ORDER you wish to have them contacted. The preferred
+ server list is a space separated list of IP addresses.
+ Providing port numbers is optional, and when not supplied,
+ port 389 is assumed. For an LDAP server running on this
+ machine, at port 389, use "127.0.0.1:389".
+
+EOF
+ ;;
+ nisLDAPproxyUser_help) cat <<EOF
+
+HELP - The bind DN of the proxy user the ypserv to read or write
+ from or to LDAP. Assumed to have the appropriate permission
+ to read and modify LDAP data. There is no default value. If
+ the value ends with a comma, the value of the context for
+ the current domain (as defined by a nisLDAPdomainContext
+ attribute (NISLDAPmapping(4))) is appended.
+
+EOF
+ ;;
+ nisLDAPbindTimeout_help) cat <<EOF
+
+HELP - The amount of time in seconds after which an LDAP bind operation
+ will timeout. Default is $DEF_nisLDAPbindTimeout seconds.
+ Decimal values are allowed.
+
+EOF
+ ;;
+ nisLDAPsearchTimeout_help) cat <<EOF
+
+HELP - The amount of time in seconds after which an LDAP search operation
+ will timeout. Default is $DEF_nisLDAPsearchTimeout seconds.
+ Decimal values are allowed.
+
+EOF
+ ;;
+ nisLDAPmodifyTimeout_help) cat <<EOF
+
+HELP - The amount of time in seconds after which an LDAP modify operation
+ will timeout. Default is $DEF_nisLDAPmodifyTimeout seconds.
+ Decimal values are allowed.
+
+EOF
+ ;;
+ nisLDAPaddTimeout_help) cat <<EOF
+
+HELP - The amount of time in seconds after which an LDAP add operation
+ will timeout. Default is $DEF_nisLDAPaddTimeout seconds.
+ Decimal values are allowed.
+
+EOF
+ ;;
+ nisLDAPdeleteTimeout_help) cat <<EOF
+
+HELP - The amount of time in seconds after which an LDAP delete operation
+ will timeout. Default is $DEF_nisLDAPdeleteTimeout seconds.
+ Decimal values are allowed.
+
+EOF
+ ;;
+ nisLDAPsearchTimeLimit_help) cat <<EOF
+
+HELP - Establish a value for the LDAP_OPT_TIMELIMIT option, which
+ suggests a time limit for the search operation on the LDAP
+ server. The server may impose its own constraints on possible
+ values. See your LDAP server documentation. The default is the
+ nisLDAPsearchTimeout ($DEF_nisLDAPsearchTimeout seconds) value.
+ Only integer values are allowed.
+
+ Since the nisLDAPsearchTimeout limits the amount of time the
+ client ypserv will wait for completion of a search operation,
+ setting the nisLDAPsearchTimeLimit larger than the
+ nisLDAPsearchTimeout is not recommended.
+
+EOF
+ ;;
+ nisLDAPsearchSizeLimit_help) cat <<EOF
+
+HELP - Establish a value for the LDAP_OPT_SIZELIMIT option, which
+ suggests a size limit, in bytes, for the search results on
+ the LDAP server. The server may impose its own constraints
+ on possible values. See your LDAP server documentation. The
+ default is $DEF_nisLDAPsearchSizeLimit, which means unlimited.
+ Only integer values are allowed.
+
+EOF
+ ;;
+ nisLDAPfollowReferral_help) cat <<EOF
+
+HELP - Determines if the ypserv should follow referrals or not.
+ Recognized values are yes and no. Default is $DEF_nisLDAPfollowReferral.
+
+EOF
+ ;;
+ nisLDAPretrieveErrorAction_help) cat <<EOF
+
+HELP - If an error occurs while trying to retrieve an entry from
+ LDAP, one of the following actions can be selected:
+
+ use_cached : Retry the retrieval the number of time specified
+ by nisLDAPretrieveErrorAttempts, with the
+ nisLDAPretrieveErrorTimeout value controlling
+ the wait between each attempt.
+
+ If all attempts fail then log a warning and
+ return the value currently in the cache to the
+ client. This is the default value.
+
+ fail : Proceed as for 'use_cached' but if all attempts
+ fail return a YPERR_YPERR error to the client.
+
+EOF
+ ;;
+ nisLDAPretrieveErrorAttempts_help) cat <<EOF
+
+HELP - The number of times a failed retrieval should be retried.
+ The default is unlimited. Note while retries are made, the
+ NIS daemon will be prevented from servicing further requests.
+ Hence, values other than 1 should be used with caution.
+
+EOF
+ ;;
+ nisLDAPretrieveErrorTimeout_help) cat <<EOF
+
+HELP - The timeout (in seconds) between each new attempt to retrieve
+ LDAP data. Default is $DEF_nisLDAPretrieveErrorTimeout seconds.
+
+EOF
+ ;;
+ nisLDAPstoreErrorAction_help) cat <<EOF
+
+HELP - If an error occurs while trying to store data to the LDAP
+ repository, one of the following actions can be selected :
+
+ retry : Retry operation nisLDAPstoreErrorAttempts times with
+ nisLDAPstoreErrorTimeout seconds between each attempt.
+ Note while retries are made the NIS daemon will be
+ prevented from servicing further requests. Use with
+ caution. This is the default value.
+
+ fail : Return YPERR_YPERR error to the client.
+
+EOF
+ ;;
+ nisLDAPstoreErrorAttempts_help) cat <<EOF
+
+HELP - The number of times a failed attempt to store data to the
+ LDAP repository should be retried. The default is unlimited.
+
+ The value for nisLDAPstoreErrorAttempts is ignored unless
+ nisLDAPstoreErrorAction=retry.
+
+EOF
+ ;;
+ nisLDAPstoreErrorTimeout_help) cat <<EOF
+
+HELP - The timeout (in seconds) between each new attempt to store
+ LDAP data. Default is $DEF_nisLDAPstoreErrorTimeout seconds.
+
+ The value for nisLDAPstoreErrorTimeout is ignored unless
+ nisLDAPstoreErrorAction=retry.
+
+EOF
+ ;;
+ selectDomain4N2L_help) cat <<EOF
+
+HELP - Whether this domain needs to be served by YP to LDAP transition
+ solution. The default is no in which case the data in this
+ domain would not be taken care for transitioning to LDAP.
+
+EOF
+ ;;
+ generate_comment_info_for_cust_map_help) cat <<EOF
+
+HELP - If selected, this script will try to add relevant comments
+ in the mapping file which might help in customizing the
+ mapping information for custom maps.
+
+EOF
+ ;;
+ generate_mapping_info_for_cust_map_help) cat <<EOF
+
+HELP - If selected, this script will try to generate mapping
+ information for this map assuming it is a "simple" map.
+
+ A map is assumed to be "simple" if each entry of this map
+ has only one "key value" entry in YP, and if each map entry
+ can be represented as a single DIT string in the LDAP server.
+
+ If this map is not a simple map and you do want to store it
+ in LDAP, you have two options :
+
+ 1 - Answer yes, and this script would generate the mapping
+ information for this map assuming it is a simple map.
+ And once the execution of the script is over, you can
+ customize the mapping information by hand editing the
+ mapping file.
+
+ 2 - Answer no, and this script would not generate mapping
+ info for this map. And once the execution of the script
+ is over, you can include the customized mapping
+ information by hand editing the mapping file.
+
+EOF
+ ;;
+ nisLDAPdomainContext_help) cat <<EOF
+
+HELP - This parameter defines the context (default location) in
+ the directory tree at which all the name service entries
+ for this particular domain would be stored.
+
+EOF
+ ;;
+ nisLDAPyppasswddDomains_help) cat <<EOF
+
+HELP - Lists the domains for which password changes should be
+ made. If this is not present then the value returned by
+ 'domainname' will be used.
+
+ NIS password change requests do not specify the domains in
+ which any given password should be changed. (In traditional
+ NIS this information is effectively hard coded in the NIS
+ makefile.)
+
+EOF
+ ;;
+ custom_map_comment_char_help) cat <<EOF
+
+HELP - If selected, it will allow you to specify a character which
+ would represent the start of the special 'comment' field in
+ a given NIS map. If this attribute is not present then the
+ default comment character '#' is used.
+
+ If a map cannot contain comments then the blank comment
+ character ('') should be specified (just hit the return key).
+
+EOF
+ ;;
+ same_comment_char_help) cat <<EOF
+
+HELP - If selected, for a given map, it will allow you to specify
+ a common comment character for all the domains.
+
+ Or else by selecting NO, for the same map, you would be
+ given the option to specify different comment character
+ for different domains.
+
+EOF
+ ;;
+ secure_flag_on_help) cat <<EOF
+
+HELP - Secure flag is set on maps which are generated with
+ "makedbm -s". When converting data from LDAP to YP,
+ it adds YP_SECURE entries.
+
+EOF
+ ;;
+ secure_flag_all_domains_help) cat <<EOF
+
+HELP - If selected, it will allow you to set the secure flag on
+ for this map for all the domains.
+
+ Or else by selecting NO, you would be given the option to
+ set this flag, for the same map, on per domain basis.
+
+EOF
+ ;;
+ interdomain_flag_on_help) cat <<EOF
+
+HELP - Interdomain flag is set on a set of maps which are generated
+ with "makedbm -b". It signals NIS servers to use the domain
+ name resolver for host name and address lookups for hosts
+ not found in the maps.
+
+ If selected, it adds YP_INTERDOMAIN entries in these maps
+ when converting data from LDAP to YP.
+
+EOF
+ ;;
+ interdomain_flag_all_domains_help) cat <<EOF
+
+HELP - If selected, it will allow you to set the interdomain flag
+ on for all the domains.
+
+ Or else by selecting NO, you would be given the option to
+ set this flag on per domain basis.
+
+EOF
+ ;;
+ initialTTLlo_help) cat <<EOF
+
+HELP - The lower limit for the initial TTL (in seconds) for data
+ read from disk when the ypserv starts. If initialTTLhi also
+ is specified, the actual initialTTL will be randomly selected
+ from the interval initialTTLlo to initialTTLhi (inclusive).
+
+ Leaving the field empty yields the default value of $DEF_iTTLlo.
+
+EOF
+ ;;
+ initialTTLhi_help) cat <<EOF
+
+HELP - The upper limit for the initial TTL (in seconds).
+ If left empty, defaults to "$DEF_iTTLhi".
+
+EOF
+ ;;
+ runningTTL_help) cat <<EOF
+
+HELP - The TTL (in seconds) for data retrieved from LDAP while the
+ ypserv is running. If left empty, defaults to "$DEF_runTTL".
+
+EOF
+ ;;
+ default_ttl_help) cat <<EOF
+
+HELP - The default TTL value for each map is set to :
+ ${DEF_iTTLlo}:${DEF_iTTLhi}:${DEF_runTTL}
+
+ Select yes if you want to change the current TTL value.
+
+EOF
+ ;;
+ non_default_same_ttl_help) cat <<EOF
+
+HELP - Select yes if you want to set a new TTL value, but want
+ to keep it same for all the maps.
+
+EOF
+ ;;
+ non_default_different_ttl_help) cat <<EOF
+
+HELP - Select yes if you want to set TTL value for each map, but
+ want to keep it same for all the domains.
+
+EOF
+ ;;
+ default_different_ttl_help) cat <<EOF
+
+HELP - Select yes if you want to accept the default TTL
+ value for this map.
+
+EOF
+ ;;
+ same_ttl_across_domains_help) cat <<EOF
+
+HELP - Select yes if you want to set TTL value for the map,
+ but want to keep it same for all the domains.
+
+EOF
+ ;;
+
+ esac
+}
+
+#
+# Echo the message passed only if DEBUG is set.
+# Reduces the line width significantly.
+#
+d_echo()
+{
+[ DEBUG -eq 1 ] && echo $@
+}
+
+
+#
+# get_ans(): gets an answer from the user.
+# $1 instruction/comment/description/question
+# $2 default value
+#
+get_ans()
+{
+ if [ -z "$2" ]
+ then
+ echo "$1 \c"
+ else
+ echo "$1 [$2] \c"
+ fi
+
+ read ANS
+ if [ -z "$ANS" ]
+ then
+ ANS=$2
+ fi
+}
+
+
+#
+# get_ans_req(): gets an answer (required) from the user, NULL value not allowed.
+# $@ instruction/comment/description/question
+#
+get_ans_req()
+{
+ ANS="" # Set ANS to NULL.
+ while [ "$ANS" = "" ]
+ do
+ get_ans "$@"
+ [ "$ANS" = "" ] && echo "NULL value not allowed!"
+ done
+}
+
+
+#
+# get_integer(): Querys and verifies that number entered is integer.
+# Function will repeat prompt user for integer value.
+# $1 Message text.
+# $2 default value.
+# $3 Help argument.
+#
+get_integer()
+{
+ ANS="" # Set ANS to NULL.
+ NUM=""
+
+ get_ans "$1" "$2"
+
+ # Verify that value is integer.
+ while not_integer $ANS
+ do
+ case "$ANS" in
+ [Hh] | help | Help | \?) display_msg ${3:-sorry} ;;
+ * ) echo "Invalid value: \"${ANS}\". \c"
+ ;;
+ esac
+
+ # Get a new value.
+ get_ans "Enter an integer value:" "$2"
+ done
+ NUM=$ANS
+}
+
+
+#
+# get_number(): Querys and verifies that number entered is numeric.
+# Function will repeat prompt user for numeric value.
+# $1 Message text.
+# $2 default value.
+# $3 Help argument.
+#
+get_number()
+{
+ ANS="" # Set ANS to NULL.
+ NUM=""
+
+ get_ans "$1" "$2"
+
+ # Verify that value is numeric.
+ while not_numeric $ANS
+ do
+ case "$ANS" in
+ [Hh] | help | Help | \?) display_msg ${3:-sorry} ;;
+ * ) echo "Invalid value: \"${ANS}\". \c"
+ ;;
+ esac
+
+ # Get a new value.
+ get_ans "Enter a numeric value:" "$2"
+ done
+ NUM=$ANS
+}
+
+
+#
+# get_pos_int(): Only allows positive integer.
+#
+# $1 - Prompt message.
+# $2 - Default value (require).
+# $3 - Optional help argument.
+get_pos_int()
+{
+ while :
+ do
+ get_integer "$1" "$2" "$3"
+
+ if [ $ANS -lt 0 ]; then
+ echo "Invalid number: please enter a positive integer."
+ else
+ break # Positive integer
+ fi
+ done
+}
+
+
+#
+# get_pos_num(): Only allows positive number.
+#
+# $1 - Prompt message.
+# $2 - Default value (require).
+# $3 - Optional help argument.
+get_pos_num()
+{
+ while :
+ do
+ get_number "$1" "$2" "$3"
+
+ if [ $ANS -lt 0 ]; then
+ echo "Invalid number: please enter a positive number."
+ else
+ break # Positive number
+ fi
+ done
+}
+
+
+#
+#
+# get_passwd(): Reads a password from the user and verify with second.
+# $@ instruction/comment/description/question
+#
+get_passwd()
+{
+ [ $DEBUG -eq 1 ] && echo "In get_passwd()"
+
+ # Temporary PASSWD variables
+ _PASS1=""
+ _PASS2=""
+
+ # Handle signals, so that echo can be turned back on if Ctrl-C.
+ trap "/usr/bin/stty echo; exit" 1 2 3 6 15
+
+ /usr/bin/stty -echo # Turn echo OFF
+
+ # Endless loop that continues until passwd and re-entered passwd
+ # match.
+ while :
+ do
+ ANS="" # Set ANS to NULL.
+
+ # Don't allow NULL for first try.
+ while [ "$ANS" = "" ]
+ do
+ get_ans "$@"
+ [ "$ANS" = "" ] && echo "" && echo "NULL passwd not allowed!"
+ done
+ _PASS1=$ANS # Store first try.
+
+ # Get second try.
+ echo ""
+ get_ans "Re-enter passwd:"
+ _PASS2=$ANS
+
+ # Test if passwords are identical.
+ if [ "$_PASS1" = "$_PASS2" ]; then
+ break
+ fi
+
+ # Move cursor down to next line and print ERROR message.
+ echo ""
+ echo "ERROR: passwords don't match; try again."
+ done
+
+ /usr/bin/stty echo # Turn echo ON
+
+ # Removed signal handler
+ trap 1 2 3 6 15
+
+ echo ""
+}
+
+
+#
+# get_passwd_nochk(): Reads a password from the user w/o check.
+# $@ instruction/comment/description/question
+#
+get_passwd_nochk()
+{
+ [ $DEBUG -eq 1 ] && echo "In get_passwd_nochk()"
+
+ # Handle signals, so that echo can be turned back on if Ctrl-C.
+ trap "/usr/bin/stty echo; exit" 1 2 3 6 15
+
+ /usr/bin/stty -echo # Turn echo OFF
+
+ get_ans "$@"
+
+ /usr/bin/stty echo # Turn echo ON
+
+ # Removed signal handler
+ trap 1 2 3 6 15
+
+ echo ""
+}
+
+
+#
+# get_confirm(): Get confirmation from the user. (Y/Yes or N/No)
+# $1 - Message
+# $2 - default value.
+#
+get_confirm()
+{
+ _ANSWER=
+
+ while :
+ do
+ # Display Internal ERROR if $2 not set.
+ if [ -z "$2" ]; then
+ echo "INTERNAL ERROR: get_confirm requires 2 args, 3rd is optional."
+ exit 2
+ fi
+
+ # Display prompt.
+ echo "$1 [$2] \c"
+
+ # Get the ANSWER.
+ read _ANSWER
+ if [ "$_ANSWER" = "" ] && [ -n "$2" ] ; then
+ _ANSWER=$2
+ fi
+ case "$_ANSWER" in
+ [Yy] | yes | Yes | YES) return 1 ;;
+ [Nn] | no | No | NO) return 0 ;;
+ [Hh] | help | Help | \?) display_msg ${3:-sorry};;
+ * ) echo "Please enter y or n." ;;
+ esac
+ done
+}
+
+
+#
+# get_confirm_nodef(): Get confirmation from the user. (Y/Yes or N/No)
+# No default value supported. Returns 1 for yes.
+#
+get_confirm_nodef()
+{
+ _ANSWER=
+
+ while :
+ do
+ echo "$@ \c"
+ read _ANSWER
+ case "$_ANSWER" in
+ [Yy] | yes | Yes | YES) return 1 ;;
+ [Nn] | no | No | NO) return 0 ;;
+ * ) echo "Please enter y or n." ;;
+ esac
+ done
+}
+
+
+#
+# is_integer(): Tells if a string is numeric integer.
+# 0 = Integer
+# 1 = NOT Integer
+#
+is_integer()
+{
+ # Check for parameter.
+ if [ $# -ne 1 ]; then
+ return 1
+ fi
+
+ # Determine if integer.
+ expr "$1" + 1 > /dev/null 2>&1
+
+ if [ $? -ge 2 ]; then
+ return 1
+ fi
+
+ # Made it here, it's Numeric.
+ return 0
+}
+
+
+#
+# not_integer(): Reverses the return values of is_integer. Useful
+# for if and while statements that want to test for
+# non-integer data.
+# 0 = NOT Integer
+# 1 = Integer
+#
+not_integer()
+{
+ is_integer $1
+ if [ $? -eq 0 ]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+
+#
+# is_numeric(): Tells if a string is numeric.
+# 0 = Numeric
+# 1 = NOT Numeric
+#
+is_numeric()
+{
+ # Check for parameter.
+ if [ $# -ne 1 ]; then
+ return 1
+ fi
+
+ # Determine if numeric.
+ let _NUM="$1 + 1" > /dev/null 2>&1
+
+ if [ $? -eq 0 ]; then
+ return 0
+ fi
+
+}
+
+
+#
+# not_numeric(): Reverses the return values of is_numeric. Useful
+# for if and while statements that want to test for
+# non-numeric data.
+# 0 = NOT Numeric
+# 1 = Numeric
+#
+not_numeric()
+{
+ is_numeric $1
+ if [ $? -eq 0 ]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+
+#
+# domain_2_dc(): Convert a domain name into dc string.
+# $1 .. Domain name.
+#
+domain_2_dc()
+{
+ _DOM=$1 # Domain parameter.
+ _DOM_2_DC="" # Return value from function.
+ _FIRST=1 # Flag for first time.
+
+ export _DOM_2_DC # Make visible for others.
+
+ # Convert "."'s to spaces for "for" loop.
+ domtmp="`echo ${_DOM} | tr '.' ' '`"
+ for i in $domtmp; do
+ if [ $_FIRST -eq 1 ]; then
+ _DOM_2_DC="dc=${i}"
+ _FIRST=0
+ else
+ _DOM_2_DC="${_DOM_2_DC},dc=${i}"
+ fi
+ done
+}
+
+
+#
+# is_root_user(): Check to see if logged in as super user.
+#
+is_root_user()
+{
+ case `id` in
+ uid=0\(root\)*) return 0 ;;
+ * ) return 1 ;;
+ esac
+}
+
+
+#
+# parse_arg(): Parses the command line arguments and sets the
+# appropriate variables.
+#
+parse_arg()
+{
+ while getopts ":dm:c:" ARG
+ do
+ case $ARG in
+ d) DEBUG=1;;
+
+ m) MAP_FILE=$OPTARG
+ MAPPING_FILE_SPECIFIED=1;;
+
+ c) CONFIG_FILE=$OPTARG
+ CONFIG_FILE_SPECIFIED=1;;
+
+ \?) echo "**ERROR: Invalid option '$OPTARG'"
+ display_msg usage
+ exit 1;;
+ esac
+ done
+
+ shift `expr $OPTIND - 1`
+ if [ $# -gt 0 ]; then
+ echo "**ERROR: wrong usage "
+ display_msg usage
+ exit 1
+ fi
+}
+
+
+#
+# present() : Checks if the first argument exists in the
+# argument list. Returns 0 if found, else 1.
+#
+present ()
+{
+_ELEMENT=$1
+
+shift
+ARG_LIST=$@
+
+for item in $ARG_LIST
+do
+ [ "$_ELEMENT" = "$item" ] && return 0
+done
+
+# If reached here, then the clement does not exist
+return 1
+}
+
+
+#
+# remove() : Returns a new string after removing the first
+# argument in the argument list.
+#
+remove ()
+{
+_ELEMENT=$1
+
+shift
+ARG_LIST=$@
+
+NEW_LIST=""
+
+for item in $ARG_LIST
+do
+ [ "$_ELEMENT" != "$item" ] && NEW_LIST="$NEW_LIST $item"
+done
+
+echo $NEW_LIST
+return 0
+}
+
+
+#
+# merge_lists() : Returns a list after merging elements
+# (uniquely) supplied in the argument list.
+#
+merge_lists()
+{
+MERGED_LIST=""
+
+for _VAR in "$@"
+do
+ if ! present $_VAR $MERGED_LIST; then
+ MERGED_LIST="$MERGED_LIST $_VAR"
+ fi
+done
+
+echo $MERGED_LIST
+return 0
+}
+
+
+#
+# init(): initializes variables and options
+#
+init()
+{
+# General variables.
+DEBUG=0 # Set Debug OFF
+
+MAPPING_FILE_SPECIFIED=0 # No file name passed
+CONFIG_FILE_SPECIFIED=0 # No file name passed
+
+# Prevent others from snooping
+umask 077
+
+# Set default config and mapping files.
+DEFAULT_MAP_FILE="/var/yp/NISLDAPmapping"
+DEFAULT_CONFIG_FILE="/etc/default/ypserv"
+
+MAP_FILE="$DEFAULT_MAP_FILE"
+CONFIG_FILE="$DEFAULT_CONFIG_FILE"
+
+# Set and create TMPDIR. Use a safe place to discourage hackers.
+TMPDIR="/var/yp/inityp2l"
+
+# Temporary file names to be used to prevent system starting in
+# N2L mode in case something goes wrong during file creation.
+TMPCONF="ypserv-tmp"
+TMPMAP="NISLDAPmapping-tmp"
+
+# Remove if the temp directory has been leftover
+[ -d "$TMPDIR" ] && rm -rf $TMPDIR
+mkdir $TMPDIR
+if [ $? -ne 0 ]; then
+ echo ERROR : Failed to create temp directory $TMPDIR
+ exit 1
+fi
+
+# Initialize the default NIS maps.
+DEFAULT_NIS_MAPS="passwd.byname
+ passwd.byuid
+ group.byname
+ group.bygid
+ hosts.byaddr
+ hosts.byname
+ ipnodes.byaddr
+ ipnodes.byname
+ ethers.byaddr
+ ethers.byname
+ networks.byaddr
+ networks.byname
+ rpc.bynumber
+ services.byname
+ services.byservicename
+ printers.conf.byname
+ project.byname
+ project.byprojid
+ protocols.byname
+ protocols.bynumber
+ netgroup
+ netgroup.byuser
+ netgroup.byhost
+ bootparams
+ mail.aliases
+ mail.byaddr
+ publickey.byname
+ netid.byname
+ netmasks.byaddr
+ passwd.adjunct.byname
+ group.adjunct.byname
+ timezone.byname
+ auth_attr
+ exec_attr
+ prof_attr
+ user_attr
+ audit_user
+ auto.master
+ auto.home
+ ypservers"
+
+set -A DEF_NIS_MAP_ARRAY $DEFAULT_NIS_MAPS
+
+# The default TTL maps in database ID format.
+DEF_TTL_MAPLIST="audit_user
+ auto.home
+ auto.master
+ auth_attr
+ bootparams
+ ethers
+ exec_attr
+ group
+ group.adjunct.byname
+ keys.host
+ keys.pass
+ keys.nobody
+ hosts
+ multihosts
+ ipnodes
+ multiipnodes
+ netgroup
+ networks
+ passwd
+ passwd.adjunct.byname
+ printers.conf.byname
+ prof_attr
+ project
+ protocols
+ services
+ mail.aliases
+ mail.mapping
+ netid.host
+ netid.pass
+ netmasks.byaddr
+ rpc.bynumber
+ ageing.byname
+ timezone.byname
+ user_attr
+ ypservers"
+
+
+# Initialize default values for config parameters.
+
+configDN_flag=0
+DEF_nisLDAPconfigDN=""
+DEF_TLS=none
+DEF_TLSCertificateDBPath=/var/yp/cert7.db
+DEF_nisLDAPbindTimeout=15
+DEF_nisLDAPsearchTimeout=180
+DEF_nisLDAPmodifyTimeout=15
+DEF_nisLDAPaddTimeout=15
+DEF_nisLDAPdeleteTimeout=15
+DEF_nisLDAPsearchTimeLimit=${DEF_nisLDAPsearchTimeout}
+DEF_nisLDAPsearchSizeLimit=0
+DEF_nisLDAPfollowReferral=no
+DEF_nisLDAPretrieveErrorAction=use_cached
+
+# The default is unlimited, but since it prevents the NIS daemon,
+# from servicing further requests, set 1 as the suggested value.
+SUG_nisLDAPretrieveErrorAttempts=1
+DEF_nisLDAPretrieveErrorTimeout=15
+DEF_nisLDAPstoreErrorAction=retry
+
+# The default is unlimited, but set 1 as the suggested value.
+SUG_nisLDAPstoreErrorAttempts=1
+DEF_nisLDAPstoreErrorTimeout=15
+
+# Default TTL values (in seconds) for NIS MAPS for mapping file.
+DEF_iTTLlo=1800
+DEF_iTTLhi=5400
+DEF_runTTL=3600
+
+}
+
+
+#
+# config_auth_menu_handler(): Enter the authentication method
+# for config server.
+#
+config_auth_menu_handler()
+{
+ # Display Auth menu
+ display_msg config_auth_method_menu
+
+ # Get a Valid choice.
+ while :
+ do
+ # Display appropriate prompt and get answer.
+ get_ans_req " Choose one Authentication Method (h=help):"
+
+ # Determine choice.
+ _MENU_CHOICE=$ANS
+ case "$_MENU_CHOICE" in
+ 1) _AUTHMETHOD="none"
+ break ;;
+ 2) _AUTHMETHOD="simple"
+ break ;;
+ 3) _AUTHMETHOD="sasl/cram-md5"
+ break ;;
+ 4) _AUTHMETHOD="sasl/digest-md5"
+ break ;;
+ h) display_msg auth_help ;;
+ *) echo "Please enter 1-4, or h=help." ;;
+ esac
+ done
+}
+
+
+#
+# auth_menu_handler(): Enter the Authentication method for LDAP server.
+#
+auth_menu_handler()
+{
+ # Display Auth menu
+ display_msg auth_method_menu
+
+ # Get a Valid choice.
+ while :
+ do
+ # Display appropriate prompt and get answer.
+ get_ans_req " Choose one Authentication Method (h=help):"
+
+ # Determine choice.
+ _MENU_CHOICE=$ANS
+ case "$_MENU_CHOICE" in
+ 1) _AUTHMETHOD="simple"
+ break ;;
+ 2) _AUTHMETHOD="sasl/cram-md5"
+ break ;;
+ 3) _AUTHMETHOD="sasl/digest-md5"
+ break ;;
+ h) display_msg auth_help ;;
+ *) echo "Please enter 1-3, or h=help." ;;
+ esac
+ done
+}
+
+
+#
+# tls_menu_handler(): Enter the transport layer security
+#
+tls_menu_handler()
+{
+ # Display TLS menu
+ display_msg tls_method_menu
+
+ # Get a Valid choice.
+ while :
+ do
+ # Display appropriate prompt and get answer.
+ # Default value is "none".
+
+ get_ans " Choose one Transport Layer Security Method (h=help):" "1"
+
+ # Determine choice.
+ _MENU_CHOICE=$ANS
+ case "$_MENU_CHOICE" in
+ 1) _TLSMETHOD="none"
+ break ;;
+ 2) _TLSMETHOD="ssl"
+ break ;;
+ h) display_msg tls_help ;;
+ *) echo "Please enter 1, 2, or h=help." ;;
+ esac
+ done
+}
+
+
+#
+# retrieve_error_action_menu_handler(): Enter the retrieve error action
+#
+retrieve_error_action_menu_handler()
+{
+ # Display retrieve error action menu
+ display_msg retrieve_error_action_menu
+
+ # Get a Valid choice.
+ while :
+ do
+ # Display appropriate prompt and get answer. use_cached is default
+ get_ans " Choose one retrieval error action (h=help):" "1"
+
+ # Determine choice.
+ _MENU_CHOICE=$ANS
+ case "$_MENU_CHOICE" in
+ 1) _RET_ERR_ACT="use_cached"
+ break ;;
+ 2) _RET_ERR_ACT="fail"
+ break ;;
+ h) display_msg nisLDAPretrieveErrorAction_help ;;
+ *) echo "Please enter 1, 2, or h=help." ;;
+ esac
+ done
+}
+
+
+#
+# store_error_action_menu_handler(): Enter the store error action
+#
+store_error_action_menu_handler()
+{
+ # Display store error action menu
+ display_msg store_error_action_menu
+
+ # Get a Valid choice.
+ while :
+ do
+ # Display appropriate prompt and get answer. retry is default
+ get_ans " Choose one store error action (h=help):" "1"
+
+ # Determine choice.
+ _MENU_CHOICE=$ANS
+ case "$_MENU_CHOICE" in
+ 1) _STOR_ERR_ACT="retry"
+ break ;;
+ 2) _STOR_ERR_ACT="fail"
+ break ;;
+ h) display_msg nisLDAPstoreErrorAction_help ;;
+ *) echo "Please enter 1, 2, or h=help." ;;
+ esac
+ done
+}
+
+
+#
+# cleanup(): Remove the TMPDIR and all files in it.
+#
+cleanup()
+{
+[ $DEBUG -eq 1 ] && echo "In cleanup()"
+
+# Leave the temp directory if debug is set
+[ $DEBUG -eq 0 ] && rm -rf $TMPDIR
+}
+
+
+# Save existing config file if elected
+check_back_config_file()
+{
+if [ -f $CONFIG_FILE ]; then
+ display_msg backup_config_file
+
+ get_confirm "Do you wish to continue (y/n/h)?" \
+ "n" "backup_config_file_cont_help"
+
+ if [ $? -eq 0 ]; then # if No, cleanup and exit.
+ cleanup ; exit 1
+ fi
+
+ get_confirm "Do you wish to backup the config file "${CONFIG_FILE}" (y/n/h)?" \
+ "y" "backup_config_file_help"
+
+ if [ $? -eq 1 ]; then # Save the old config file with timestamp
+
+ # SCCS converts '% H %' (without spaces) in current date during putback.
+ # So use some other combination.
+ SUFFIX=`date '+%d%h%Y.%H:%M:%S'`
+
+ cp -p $CONFIG_FILE ${CONFIG_FILE}-${SUFFIX}
+ echo " Saved existing $CONFIG_FILE as ${CONFIG_FILE}-${SUFFIX}"
+ fi
+fi
+}
+
+
+# Save existing mapping file if elected
+check_back_mapping_file()
+{
+if [ -f $MAP_FILE ]; then
+ display_msg backup_mapping_file
+
+ get_confirm "Do you wish to continue (y/n/h)?" \
+ "n" "backup_mapping_file_cont_help"
+
+ if [ $? -eq 0 ]; then # if No, cleanup and exit.
+ cleanup ; exit 1
+ fi
+
+ get_confirm "Do you wish to backup the map file "${MAP_FILE}" (y/n/h)?" \
+ "y" "backup_mapping_file_help"
+
+ if [ $? -eq 1 ]; then # if Yes, save the old map file with timestamp
+
+ # SCCS converts '% H %' (without spaces) in current date during putback.
+ # So use some other combination.
+ SUFFIX=`date '+%d%h%Y.%H:%M:%S'`
+
+ cp -p $MAP_FILE ${MAP_FILE}-${SUFFIX}
+ echo " Saved existing $MAP_FILE as ${MAP_FILE}-${SUFFIX}"
+ fi
+
+else
+ if [ "$MAP_FILE" = "$DEFAULT_MAP_FILE" ]; then
+ display_msg warn_n2l_mode
+
+ get_confirm "Do you wish to continue (y/n/h)?" \
+ "n" "warn_n2l_mode_help"
+
+ if [ $? -eq 0 ]; then
+ cleanup ; exit 1
+ fi
+ fi
+fi
+}
+
+
+put_config_file_copyright_info()
+{
+
+# Start with an emptty file, so don't append, but overwrite here.
+# Just change the name, but keep the same date and version number
+# as in the ident string of this script.
+
+grep "ident \"@(#)$PROG" $ABS_PROG | \
+ sed "s/${PROG}/${NEW_NAME}/g" > $CONFIG_FILE
+
+echo "\
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#\
+" >> $MAP_FILE
+}
+
+
+get_nisLDAPconfigDN()
+{
+while :
+do
+
+get_ans "DN for configuration information (h=help):"
+
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg nisLDAPconfigDN_help ;;
+ * ) break ;;
+esac
+done
+
+nisLDAPconfigDN="${ANS}"
+
+# Store in config file only if a non-default value is specified.
+if [ "$ANS" != "${DEF_nisLDAPconfigDN}" ]; then
+ echo "nisLDAPconfigDN=${ANS}" >> $CONFIG_FILE
+fi
+
+# Ask remaining config server related questions only if this
+# DN is set. So, if a value is specified, set a flag.
+
+[ "$ANS" != "" ] && configDN_flag=1
+}
+
+
+get_nisLDAPconfigPreferredServerList()
+{
+while :
+do
+
+get_ans_req "Preferred server list for configuration information (h=help):"
+
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg nisLDAPconfigPreferredServerList_help ;;
+ * ) break ;;
+esac
+done
+
+nisLDAPconfigPreferredServerList=${ANS}
+echo "nisLDAPconfigPreferredServerList=${ANS}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPconfigAuthenticationMethod()
+{
+_AUTHMETHOD=""
+
+echo "Select the Authentication Method for configuration server :"
+config_auth_menu_handler
+
+nisLDAPconfigAuthenticationMethod=${_AUTHMETHOD}
+echo "nisLDAPconfigAuthenticationMethod=${_AUTHMETHOD}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPconfigTLS()
+{
+_TLSMETHOD=""
+
+echo "Select the Transport Layer Security (TLS) for configuration server :"
+tls_menu_handler
+
+nisLDAPconfigTLS=${_TLSMETHOD}
+
+# Store in config file only if a non-default value is specified.
+if [ "${_TLSMETHOD}" != "${DEF_TLS}" ]; then
+ echo "nisLDAPconfigTLS=${_TLSMETHOD}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPconfigTLSCertificateDBPath()
+{
+while :
+do
+
+get_ans "TLS Certificate DB for configuration server (h=help):"\
+ "${DEF_TLSCertificateDBPath}"
+
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg TLSCertificateDBPath_help ;;
+ * ) break ;;
+esac
+done
+
+nisLDAPconfigTLSCertificateDBPath=${ANS}
+
+# Store in config file only if a non-default value is specified.
+if [ "$ANS" != "${DEF_TLSCertificateDBPath}" ]; then
+ echo "nisLDAPconfigTLSCertificateDBPath=${ANS}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPconfigProxyUser()
+{
+while :
+do
+
+get_ans_req "Proxy user bind DN to obtain configuration information (h=help):"
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg nisLDAPconfigProxyUser_help ;;
+ * ) break ;;
+esac
+done
+
+nisLDAPconfigProxyUser=${ANS}
+echo "nisLDAPconfigProxyUser=${ANS}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPconfigProxyPassword()
+{
+get_passwd "Proxy user password to obtain configuration information :"
+nisLDAPconfigProxyPassword=${ANS}
+
+echo "nisLDAPconfigProxyPassword=${ANS}" >> $CONFIG_FILE
+
+display_msg ProxyPassword_warn
+}
+
+
+get_preferredServerList()
+{
+while :
+do
+
+get_ans_req "Preferred server list for mapping data to/from LDAP (h=help):"
+
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg preferredServerList_help ;;
+ * ) break ;;
+esac
+done
+
+preferredServerList=${ANS}
+echo "preferredServerList=${ANS}" >> $CONFIG_FILE
+}
+
+
+get_authenticationMethod()
+{
+_AUTHMETHOD=""
+
+echo "Select the Authentication Method for mapping data to/from LDAP :"
+auth_menu_handler
+
+authenticationMethod=${_AUTHMETHOD}
+echo "authenticationMethod=${_AUTHMETHOD}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPTLS()
+{
+_TLSMETHOD=""
+
+echo "Select the Transport Layer Security (TLS) for mapping data to/from LDAP :"
+tls_menu_handler
+
+nisLDAPTLS=${_TLSMETHOD}
+
+# Store in config file only if a non-default value is specified.
+if [ "${_TLSMETHOD}" != "${DEF_TLS}" ]; then
+ echo "nisLDAPTLS=${_TLSMETHOD}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPTLSCertificateDBPath()
+{
+while :
+do
+
+get_ans "TLS Certificate DB for LDAP data server (h=help):"\
+ "${DEF_nisLDAPTLSCertificateDBPath}"
+
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg TLSCertificateDBPath_help ;;
+ * ) break ;;
+esac
+done
+
+nisLDAPTLSCertificateDBPath=${ANS}
+
+# Store in config file only if a non-default value is specified.
+if [ "$ANS" != "${DEF_TLSCertificateDBPath}" ]; then
+ echo "nisLDAPTLSCertificateDBPath=${ANS}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPproxyUser()
+{
+while :
+do
+
+get_ans_req "Proxy user bind DN to read/write data from/to LDAP (h=help):"
+
+# If help continue, otherwise break.
+case "$ANS" in
+ [Hh] | help | Help | \?) display_msg nisLDAPproxyUser_help ;;
+ * ) break ;;
+esac
+done
+
+nisLDAPproxyUser=${ANS}
+echo "nisLDAPproxyUser=${ANS}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPproxyPassword()
+{
+get_passwd "Proxy user password to read/write data from/to LDAP :"
+nisLDAPproxyPassword=${ANS}
+
+echo "nisLDAPproxyPassword=${ANS}" >> $CONFIG_FILE
+
+display_msg ProxyPassword_warn
+}
+
+
+get_nisLDAPbindTimeout()
+{
+get_pos_int "Timeout value (in seconds) for LDAP bind operation (h=help):" \
+ "${DEF_nisLDAPbindTimeout}" "nisLDAPbindTimeout_help"
+
+nisLDAPbindTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPbindTimeout} ]; then
+ echo "nisLDAPbindTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPsearchTimeout()
+{
+get_pos_int "Timeout value (in seconds) for LDAP search operation (h=help):" \
+ "${DEF_nisLDAPsearchTimeout}" "nisLDAPsearchTimeout_help"
+
+nisLDAPsearchTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPsearchTimeout} ]; then
+ echo "nisLDAPsearchTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPmodifyTimeout()
+{
+get_pos_int "Timeout value (in seconds) for LDAP modify operation (h=help):" \
+ "${DEF_nisLDAPmodifyTimeout}" "nisLDAPmodifyTimeout_help"
+
+nisLDAPmodifyTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPmodifyTimeout} ]; then
+ echo "nisLDAPmodifyTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPaddTimeout()
+{
+get_pos_int "Timeout value (in seconds) for LDAP add operation (h=help):" \
+ "${DEF_nisLDAPaddTimeout}" "nisLDAPaddTimeout_help"
+
+nisLDAPaddTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPaddTimeout} ]; then
+ echo "nisLDAPaddTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPdeleteTimeout()
+{
+get_pos_int "Timeout value (in seconds) for LDAP delete operation (h=help):" \
+ "${DEF_nisLDAPdeleteTimeout}" "nisLDAPdeleteTimeout_help"
+
+nisLDAPdeleteTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPdeleteTimeout} ]; then
+ echo "nisLDAPdeleteTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPsearchTimeLimit()
+{
+get_pos_int "Time limit (in seconds) for search operation on LDAP server (h=help):" \
+ "${DEF_nisLDAPsearchTimeLimit}" "nisLDAPsearchTimeLimit_help"
+
+nisLDAPsearchTimeLimit=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPsearchTimeLimit} ]; then
+ echo "nisLDAPsearchTimeLimit=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPsearchSizeLimit()
+{
+get_pos_int "Size limit (in bytes) for search operation on LDAP server (h=help):" \
+ "${DEF_nisLDAPsearchSizeLimit}" "nisLDAPsearchSizeLimit_help"
+
+nisLDAPsearchSizeLimit=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPsearchSizeLimit} ]; then
+ echo "nisLDAPsearchSizeLimit=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPfollowReferral()
+{
+get_confirm "Should the ypserv follow LDAP referrals (y/n/h):" \
+ "n" "nisLDAPfollowReferral_help"
+
+if [ $? -eq 1 ]; then
+ _ANS="yes"
+else
+ _ANS="no"
+fi
+
+# Store in config file only if a non-default value is specified.
+if [ "${_ANS}" != "${DEF_nisLDAPfollowReferral}" ]; then
+ echo "nisLDAPfollowReferral=${_ANS}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPretrieveErrorAction()
+{
+_RET_ERR_ACT=""
+
+echo "Select the action to be taken in case of LDAP retrieval error :"
+retrieve_error_action_menu_handler
+
+nisLDAPretrieveErrorAction=${_RET_ERR_ACT}
+
+# Store in config file only if a non-default value is specified.
+if [ "${_RET_ERR_ACT}" != "${DEF_nisLDAPretrieveErrorAction}" ]; then
+ echo "nisLDAPretrieveErrorAction=${_RET_ERR_ACT}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPretrieveErrorAttempts()
+{
+
+get_pos_int "Number of attempts in case of LDAP retrieval error (h=help):" \
+ "$SUG_nisLDAPretrieveErrorAttempts" \
+ "nisLDAPretrieveErrorAttempts_help"
+
+nisLDAPretrieveErrorAttempts=${NUM}
+
+echo "nisLDAPretrieveErrorAttempts=${NUM}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPretrieveErrorTimeout()
+{
+# if nisLDAPretrieveErrorAttempts=0, then no point in asking
+# for timeout vales as it is ignored anyway.
+
+[ $nisLDAPretrieveErrorAttempts -eq 0 ] && return 0
+
+get_pos_int "Timeout (in seconds) between each new attempt to retrieve LDAP data (h=help):"\
+ "${DEF_nisLDAPretrieveErrorTimeout}" \
+ "nisLDAPretrieveErrorTimeout_help"
+
+nisLDAPretrieveErrorTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPretrieveErrorTimeout} ]; then
+ echo "nisLDAPretrieveErrorTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPstoreErrorAction()
+{
+_STOR_ERR_ACT=""
+
+echo "Select the action to be taken in case of LDAP store error :"
+store_error_action_menu_handler
+
+nisLDAPstoreErrorAction=${_STOR_ERR_ACT}
+
+# Store in config file only if a non-default value is specified.
+if [ "${_STOR_ERR_ACT}" != "${DEF_nisLDAPstoreErrorAction}" ]; then
+ echo "nisLDAPstoreErrorAction=${_STOR_ERR_ACT}" >> $CONFIG_FILE
+fi
+}
+
+
+get_nisLDAPstoreErrorAttempts()
+{
+
+# if nisLDAPstoreErrorAction="fail", then no point in asking
+# for no. of attempts or timeout vales as they are ignored.
+
+[ "$nisLDAPstoreErrorAction" = "fail" ] && return 0
+
+get_pos_int "Number of attempts in case of LDAP store error (h=help):" \
+ "$SUG_nisLDAPstoreErrorAttempts" \
+ "nisLDAPstoreErrorAttempts_help"
+
+nisLDAPstoreErrorAttempts=${NUM}
+
+echo "nisLDAPstoreErrorAttempts=${NUM}" >> $CONFIG_FILE
+}
+
+
+get_nisLDAPstoreErrorTimeout()
+{
+
+# if nisLDAPstoreErrorAction="fail", then no point in asking
+# for no. of attempts or timeout vales as they are ignored.
+
+[ "$nisLDAPstoreErrorAction" = "fail" ] && return 0
+
+# Similarly, if nisLDAPstoreErrorAttempts=0, ignore this question.
+
+[ $nisLDAPstoreErrorAttempts -eq 0 ] && return 0
+
+get_pos_int "Timeout (in seconds) between each new attempt to write LDAP data (h=help):"\
+ "${DEF_nisLDAPstoreErrorTimeout}" \
+ "nisLDAPstoreErrorTimeout_help"
+
+nisLDAPstoreErrorTimeout=${NUM}
+
+# Store in config file only if a non-default value is specified.
+if [ $NUM -ne ${DEF_nisLDAPstoreErrorTimeout} ]; then
+ echo "nisLDAPstoreErrorTimeout=${NUM}" >> $CONFIG_FILE
+fi
+}
+
+
+
+create_config_file()
+{
+
+# To prevent from leaving a partial config file in case some error or
+# signal takes place, store the output being generated in a temporary
+# file first, and move it at the final destination only at the end if
+# everything goes fine.
+
+_CONFIG_FILE=$CONFIG_FILE
+CONFIG_FILE=${TMPDIR}/${TMPCONF}.$$
+
+echo "Generating config file temporarily as \"${CONFIG_FILE}\""
+
+# Truncate the file before we append anything.
+# Place copyright information
+put_config_file_copyright_info
+
+# Filter out all the YP domains in /var/yp
+# The list of domains is stored in list "VARYP_DMN_LIST"
+
+echo "\
+#
+# Configuration file for ypserv(1M); see ypserv(4) for more information,
+# and NISLDAPmapping(4) for configuration of NIS to LDAP mapping.
+
+# Unless otherwise noted, commented lines show default values.
+" >> $CONFIG_FILE
+
+echo "\
+# Where to look for configuration information in LDAP. Leave empty or
+# undefined to use this file, in which case the values of the other
+# 'nisLdapConfig*' attributes are ignored.
+#
+#nisLDAPconfigDN=\
+" >> $CONFIG_FILE
+
+get_nisLDAPconfigDN
+
+echo "
+
+# Server(s) for configuration information. There is no default;
+# use the value on the line below for an LDAP server running on
+# this machine, at port 389.
+#nisLDAPconfigPreferredServerList=127.0.0.1:389\
+" >> $CONFIG_FILE
+
+[ $configDN_flag -eq 1 ] && get_nisLDAPconfigPreferredServerList
+
+echo "
+
+# Authentication method(s) to obtain configuration information.
+#\
+" >> $CONFIG_FILE
+
+[ $configDN_flag -eq 1 ] && get_nisLDAPconfigAuthenticationMethod
+
+echo "
+
+# Transport layer security for configuration information
+#
+#nisLDAPconfigTLS=${DEF_TLS}\
+" >> $CONFIG_FILE
+
+[ $configDN_flag -eq 1 ] && get_nisLDAPconfigTLS
+
+echo "
+
+# Certificate DB for transport layer security
+#
+#nisLDAPconfigTLSCertificateDBPath=${DEF_TLSCertificateDBPath}\
+" >> $CONFIG_FILE
+
+# ask for Certificate DB only if SSL is set
+if [ "${nisLDAPconfigTLS}" = "ssl" ]; then
+ [ $configDN_flag -eq 1 ] && get_nisLDAPconfigTLSCertificateDBPath
+fi
+
+echo "
+
+# Proxy user(s) to obtain configuration information. The line below
+# is an example of the format.
+#
+#nisLDAPconfigProxyUser=cn=nisAdmin,ou=People,\
+" >> $CONFIG_FILE
+
+# Ask proxy user bind DN only if needed.
+if [ "${nisLDAPconfigAuthenticationMethod}" != "none" ]; then
+ [ $configDN_flag -eq 1 ] && get_nisLDAPconfigProxyUser
+fi
+
+echo "
+
+# Password for proxy user. Must be supplied if the authentication method
+# requires a password. If a password appears in this file, it should be
+# protected appropriately against access by unauthorized users.
+#
+#nisLDAPconfigProxyPassword=\
+" >> $CONFIG_FILE
+
+if [ "${nisLDAPconfigAuthenticationMethod}" != "none" ]; then
+ [ $configDN_flag -eq 1 ] && get_nisLDAPconfigProxyPassword
+fi
+
+echo "
+
+# Server list for mapping data to/from LDAP. There is no default;
+# use the value on the line below for an LDAP server running on
+# this machine, at port 389.
+#preferredServerList=127.0.0.1:389\
+" >> $CONFIG_FILE
+
+get_preferredServerList
+
+echo "
+
+# Authentication method for mapping data to/from LDAP
+#\
+" >> $CONFIG_FILE
+
+get_authenticationMethod
+
+echo "
+
+# Transport layer security for mapping data to/from LDAP.
+#
+#nisLDAPTLS=${DEF_TLS}\
+" >> $CONFIG_FILE
+
+get_nisLDAPTLS
+
+echo "
+
+# Certificate DB for transport layer security
+#
+#nisLDAPTLSCertificateDBPath=${DEF_TLSCertificateDBPath}\
+" >> $CONFIG_FILE
+
+# ask for Certificate DB only if SSL is set
+if [ "${nisLDAPTLS}" = "ssl" ]; then
+ get_nisLDAPTLSCertificateDBPath
+fi
+
+echo "
+
+# Proxy user for ypserv. Assumed to have appropriate permission to read
+# and/or create or modify LDAP data. The line below is an example of the
+# format.
+#
+#nisLDAPproxyUser=cn=nisAdmin,ou=People,\
+" >> $CONFIG_FILE
+
+# Ask proxy user bind DN only if needed.
+if [ "${authenticationMethod}" != "none" ]; then
+ get_nisLDAPproxyUser
+fi
+
+echo "
+
+# Password for proxy user. Must be supplied if the authentication method
+# requires a password. If a password appears in this file, it should be
+# protected appropriately against unauthorized access.
+#
+#nisLDAPproxyPassword=\
+" >> $CONFIG_FILE
+
+if [ "${authenticationMethod}" != "none" ]; then
+ get_nisLDAPproxyPassword
+fi
+
+echo "
+
+# Timeouts and time/size limits for LDAP operations.
+#
+#nisLDAPbindTimeout=${DEF_nisLDAPbindTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPbindTimeout
+
+echo "
+#nisLDAPsearchTimeout=${DEF_nisLDAPsearchTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPsearchTimeout
+
+echo "
+#nisLDAPmodifyTimeout=${DEF_nisLDAPmodifyTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPmodifyTimeout
+
+echo "
+#nisLDAPaddTimeout=${DEF_nisLDAPaddTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPaddTimeout
+
+echo "
+#nisLDAPdeleteTimeout=${DEF_nisLDAPdeleteTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPdeleteTimeout
+
+echo "
+#nisLDAPsearchTimeLimit=${DEF_nisLDAPsearchTimeLimit}\
+" >> $CONFIG_FILE
+
+get_nisLDAPsearchTimeLimit
+
+echo "
+#nisLDAPsearchSizeLimit=${DEF_nisLDAPsearchSizeLimit}\
+" >> $CONFIG_FILE
+
+get_nisLDAPsearchSizeLimit
+
+echo "
+
+# Should the ypserv follow LDAP referrals ?
+#
+#nisLDAPfollowReferral=${DEF_nisLDAPfollowReferral}\
+" >> $CONFIG_FILE
+
+get_nisLDAPfollowReferral
+
+echo "
+
+# Action, number of attempts, and timeout following an LDAP retrieval error
+#
+#nisLDAPretrieveErrorAction=${DEF_nisLDAPretrieveErrorAction}\
+" >> $CONFIG_FILE
+
+get_nisLDAPretrieveErrorAction
+
+echo "
+#nisLDAPretrieveErrorAttempts=\
+" >> $CONFIG_FILE
+
+get_nisLDAPretrieveErrorAttempts
+
+echo "
+#nisLDAPretrieveErrorTimeout=${DEF_nisLDAPretrieveErrorTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPretrieveErrorTimeout
+
+echo "
+
+# Action, number of attempts, and timeout following an LDAP store error
+#
+#nisLDAPstoreErrorAction=${DEF_nisLDAPstoreErrorAction}\
+" >> $CONFIG_FILE
+
+get_nisLDAPstoreErrorAction
+
+echo "
+#nisLDAPstoreErrorAttempts=\
+" >> $CONFIG_FILE
+
+get_nisLDAPstoreErrorAttempts
+
+echo "
+#nisLDAPstoreErrorTimeout=${DEF_nisLDAPstoreErrorTimeout}\
+" >> $CONFIG_FILE
+
+get_nisLDAPstoreErrorTimeout
+
+
+# We are done, so move back the config file from temp. location
+# to actual location.
+# In case the config file name has a directory component which does
+# not exist, then create it now, otherwise 'mv' will return error.
+
+DIR_TO_CREATE=`dirname ${_CONFIG_FILE}`
+mkdir -p ${DIR_TO_CREATE}
+
+echo "Moving output from temporary file ($CONFIG_FILE) to actual file ($_CONFIG_FILE)"
+mv $CONFIG_FILE $_CONFIG_FILE
+
+# Revert back the config file name in case needed.
+CONFIG_FILE=$_CONFIG_FILE
+echo "Finished creation of config file ( $_CONFIG_FILE )"
+
+}
+
+
+put_mapping_file_copyright_info()
+{
+
+# Start with an emptty file, so don't append, but overwrite here.
+# Just change the name and add the word pragma, but keep the same
+# date and version number as in the ident string of this script.
+
+grep "ident \"@(#)$PROG" $ABS_PROG | \
+ sed "s/ ident/pragma ident/g" | \
+ sed "s/${PROG}/${NEW_NAME}/g" > $MAP_FILE
+
+echo "\
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#-------------------------------------------------------------------
+#\
+" >> $MAP_FILE
+}
+
+
+#
+# Filter out all the YP domains in /var/yp
+# The list of domains is stored in list "VARYP_DMN_LIST"
+#
+create_all_var_yp_domain_list()
+{
+VARYP_DMN_LIST=""
+
+for entry in /var/yp/*
+do
+ DMN=`basename $entry`
+ if [ -d "/var/yp/$DMN" ] && [ -f "/var/yp/binding/$DMN/ypservers" ]
+ then
+ VARYP_DMN_LIST="$VARYP_DMN_LIST $DMN"
+ fi
+done
+
+# d_echo VARYP_DMN_LIST = "$VARYP_DMN_LIST"
+[ $DEBUG -eq 1 ] && echo VARYP_DMN_LIST = "$VARYP_DMN_LIST"
+}
+
+
+#
+# Ask user which domains would be served by N2L
+# The list of N2L domains is stored in global array
+# "N2L_DMN_LIST" and number of domains in N2L_DMN_CNT
+#
+create_n2l_domain_list()
+{
+# First make a list of all the domains in /var/yp
+create_all_var_yp_domain_list
+
+# Now identify those to be served by N2L
+let count=0
+
+for DMN in $VARYP_DMN_LIST
+do
+ get_confirm "Do you want to store maps from ${DMN} domain to LDAP (y/n/h):" \
+ "n" "selectDomain4N2L_help"
+
+ if [ $? -eq 1 ]; then
+ N2L_DMN_LIST[count]=$DMN
+ let count="count + 1"
+ fi
+
+done
+N2L_DMN_CNT=$count
+
+[ $DEBUG -eq 1 ] && echo N2L_DMN_LIST=${N2L_DMN_LIST[*]}
+[ $DEBUG -eq 1 ] && echo N2L_DMN_CNT=$N2L_DMN_CNT
+}
+
+
+#
+# Make various lists for different types of maps for each N2L domain
+# and ask user if mapping information and comments need to be generated
+# for custom maps.
+#
+# This function looks big, but since KSH does not support 2-D arrays, or
+# two level of dereferencing, it forced to have so many lists and arrays.
+# Lists are better for adding or removing elements, and arrays are better
+# for accessing with index and in knowing the no. of elements.
+#
+create_map_lists()
+{
+# Initialize them with no maps.
+ALL_DMN_ALL_MAPLIST=""
+ALL_DMN_DEF_MAPLIST=""
+ALL_DMN_CUST_MAPLIST=""
+ALL_DMN_AUTO_CUST_MAPLIST=""
+
+# Default to don't generate custom mapping info or comment info.
+CUST_MAP_NEEDED=0
+CUST_CMT_NEEDED=0
+
+let count=0
+
+while (( $count < $N2L_DMN_CNT ))
+do
+ DMN=${N2L_DMN_LIST[count]}
+ MAPDIR=/var/yp/${DMN}
+
+ # Initialize per domain lists to NULL.
+ ALL_MAPLIST=""
+ DEF_MAPLIST=""
+ CUST_MAPLIST=""
+ AUTO_CUST_MAPLIST=""
+
+ for dbmfile in $MAPDIR/*.dir
+ do
+ MAP=`basename $dbmfile .dir`
+
+ # Ignore N2L maps (those with "LDAP_" prefix and ageing.byname)
+ if [[ $MAP != LDAP_* ]] && [[ $MAP != "" ]] && \
+ [ -f $MAPDIR/${MAP}.pag ] && [[ $MAP != ageing.byname ]]
+ then
+ ALL_MAPLIST="$ALL_MAPLIST $MAP"
+
+ if present $MAP $DEFAULT_NIS_MAPS
+ then
+ DEF_MAPLIST="$DEF_MAPLIST $MAP"
+
+ elif [[ $MAP = auto.* ]]
+ then
+ AUTO_CUST_MAPLIST="$AUTO_CUST_MAPLIST $MAP"
+
+ else
+ # If we reached here, means it is custom map.
+ get_confirm "Do you want the mapping information to be generated for \"$MAP\" map of $DMN domain (y/n/h)?" \
+ "n" "generate_mapping_info_for_cust_map_help"
+
+ if [ $? -eq 1 ]
+ then
+ CUST_MAPLIST="$CUST_MAPLIST $MAP"
+ else
+ # If a customer map is not desired, then delete it from
+ # all maplist too.
+ ALL_MAPLIST=$(remove $MAP $ALL_MAPLIST)
+ fi
+
+ fi
+
+ fi
+
+ done
+
+ # Make ALL_DMN lists as they are very helpful in checking if a map exists.
+ ALL_DMN_ALL_MAPLIST=$(merge_lists $ALL_DMN_ALL_MAPLIST $ALL_MAPLIST)
+ ALL_DMN_DEF_MAPLIST=$(merge_lists $ALL_DMN_DEF_MAPLIST $DEF_MAPLIST)
+ ALL_DMN_CUST_MAPLIST=$(merge_lists $ALL_DMN_CUST_MAPLIST $CUST_MAPLIST)
+ ALL_DMN_AUTO_CUST_MAPLIST=$(merge_lists $ALL_DMN_AUTO_CUST_MAPLIST \
+ $AUTO_CUST_MAPLIST)
+
+ # Store per domain lists in arrays.
+ ALL_MAPS[$count]="$ALL_MAPLIST"
+ DEF_MAPS[$count]="$DEF_MAPLIST"
+ CUST_MAPS[$count]="$CUST_MAPLIST"
+ AUTO_CUST_MAPS[$count]="$AUTO_CUST_MAPLIST"
+
+ [ $DEBUG -eq 1 ] && echo ALL_MAPS[$DMN] = ${ALL_MAPS[$count]}
+ [ $DEBUG -eq 1 ] && echo DEF_MAPS[$DMN] = ${DEF_MAPS[$count]}
+ [ $DEBUG -eq 1 ] && echo CUST_MAPS[$DMN] = ${CUST_MAPS[$count]}
+ [ $DEBUG -eq 1 ] && echo AUTO_CUST_MAPS[$DMN] = ${AUTO_CUST_MAPS[$count]}
+
+ let count="count + 1"
+done
+
+[ $DEBUG -eq 1 ] && echo ALL_DMN_ALL_MAPLIST = $ALL_DMN_ALL_MAPLIST
+[ $DEBUG -eq 1 ] && echo ALL_DMN_DEF_MAPLIST = $ALL_DMN_DEF_MAPLIST
+[ $DEBUG -eq 1 ] && echo ALL_DMN_CUST_MAPLIST = $ALL_DMN_CUST_MAPLIST
+[ $DEBUG -eq 1 ] && echo ALL_DMN_AUTO_CUST_MAPLIST = $ALL_DMN_AUTO_CUST_MAPLIST
+
+# Store all domain lists in array too.
+set -A ALL_DMN_ALL_MAPS $ALL_DMN_ALL_MAPLIST
+set -A ALL_DMN_DEF_MAPS $ALL_DMN_DEF_MAPLIST
+set -A ALL_DMN_CUST_MAPS $ALL_DMN_CUST_MAPLIST
+set -A ALL_DMN_AUTO_CUST_MAPS $ALL_DMN_AUTO_CUST_MAPLIST
+
+# A positive customer map count implies custom mapping information
+# is required. Set this flag.
+[ ${#ALL_DMN_CUST_MAPS[*]} -gt 0 ] && CUST_MAP_NEEDED=1
+
+# Give bit of info, and ask if comments need to be placed in mapping file
+echo "
+ This script can place relevant information regarding custom
+ maps at appropriate places in the mapping file which can be
+ helpful in customizing this file.
+"
+
+get_confirm "Do you want such information to be generated (y/n/h)?" \
+ "n" "generate_comment_info_for_cust_map_help"
+
+[ $? -eq 1 ] && CUST_CMT_NEEDED=1
+
+[ $DEBUG -eq 1 ] && echo CUST_MAP_NEEDED = $CUST_MAP_NEEDED
+[ $DEBUG -eq 1 ] && echo CUST_CMT_NEEDED = $CUST_CMT_NEEDED
+
+}
+
+
+#
+# Ask user the context for each (N2l) domain
+#
+get_nisLDAPdomainContext()
+{
+echo "
+# List domains and contexts
+" >> $MAP_FILE
+
+for DMN in ${N2L_DMN_LIST[*]}
+do
+ while :
+ do
+ # Convert to domain in dc format for default choice
+ domain_2_dc $DMN
+
+ get_ans "Enter the naming context for $DMN domain (h=help):"\
+ "$_DOM_2_DC"
+
+ # If help continue, otherwise break.
+ case "$ANS" in
+ [Hh] | help | Help | \?) display_msg nisLDAPdomainContext_help ;;
+ * ) break ;;
+ esac
+ done
+
+ # If a value is specified, set it, and save in mapping file too.
+ if [ "$ANS" != "" ]; then
+ echo "nisLDAPdomainContext $DMN : ${ANS}" >> $MAP_FILE
+ fi
+
+ [ $DEBUG -eq 1 ] && echo "nisLDAPdomainContext $DMN : ${ANS}"
+done
+}
+
+
+#
+# Ask user the domains for which passwords should be changed
+#
+get_nisLDAPyppasswddDomains()
+{
+
+echo "
+# List domains for which passwords should be changed. If this is not
+# present then the value returned by 'domainname' will be used.
+" >> $MAP_FILE
+
+for DMN in ${N2L_DMN_LIST[*]}
+do
+ get_confirm "Enable password changes for ${DMN} domain (y/n/h)? " \
+ "n" "nisLDAPyppasswddDomains_help"
+
+ if [ $? -eq 1 ]; then
+ echo "nisLDAPyppasswddDomains $DMN" >> $MAP_FILE
+ fi
+done
+
+echo "
+#
+#-------------------------------------------------------------------
+#\
+" >> $MAP_FILE
+}
+
+
+#
+# Create NIS databaseId mappings (aliases)
+#
+create_nisLDAPdatabaseIdMapping()
+{
+echo '
+# Associate map names with databaseIds (aliases)
+
+# Standard maps
+nisLDAPdatabaseIdMapping ethers: ethers.byaddr ethers.byname
+nisLDAPdatabaseIdMapping group: group.bygid group.byname
+nisLDAPdatabaseIdMapping hosts:[addr="[0-9]*.[0-9]*.[0-9]*.[0-9]*"] \
+ hosts.byaddr hosts.byname
+# Special mapping to handle the YP_MULTI cases
+nisLDAPdatabaseIdMapping multihosts: \
+ [addr="[0-9]*.[0-9]*.[0-9]*.[0-9]*,*"] \
+ hosts.byname
+nisLDAPdatabaseIdMapping networks: networks.byaddr networks.byname
+nisLDAPdatabaseIdMapping project: project.byname project.byprojid
+nisLDAPdatabaseIdMapping protocols: protocols.byname protocols.bynumber
+nisLDAPdatabaseIdMapping services: services.byname services.byservicename
+
+# netid.byname is built up from the hosts and passwd files using different
+# mappings. It thus has two associated nisLDAPdatabaseIdMappings.
+nisLDAPdatabaseIdMapping netid.host:[number="0"] netid.byname
+nisLDAPdatabaseIdMapping netid.pass:[number="[1-9]*"] netid.byname
+
+# The next two are special databaseIds. They associate maps with databaseIds
+# but additionally identify which maps contain password and password adjunct
+# information for yppasswdd.
+nisLDAPdatabaseIdMapping passwd: passwd.byname passwd.byuid
+
+# mail.byaddr needs to select entries of the form x@y or x!y
+nisLDAPdatabaseIdMapping mail.mapping:[rf_key="*@*", rf_key="*!*"] \
+ mail.byaddr
+
+# publickey.byname
+# Each entry in publickey map consists of a network user name which
+# may refer to a host or a user. It also contains a default entry for nobody.
+# Hence, we need three nisLDAPdatabaseIdmappings to support the three
+# different types of keys.
+nisLDAPdatabaseIdMapping keys.host:[rf_key="unix.[a-zA-Z]*@*"] \
+ publickey.byname
+nisLDAPdatabaseIdMapping keys.pass:[rf_key="unix.[0-9]*@*"] \
+ publickey.byname
+nisLDAPdatabaseIdMapping keys.nobody:[rf_key="nobody"] publickey.byname
+
+# Single standard maps. No point aliasing.
+# mail.aliases
+# netmasks.byaddr
+# rpc.bynumber
+# ypservers
+
+# Other maps
+# ipnodes looks identical to hosts but maps to a different context.
+nisLDAPdatabaseIdMapping ipnodes:[addr="*:*"] \
+ ipnodes.byaddr ipnodes.byname
+# Special mapping to handle the YP_MULTI cases
+nisLDAPdatabaseIdMapping multiipnodes: \
+ [addr="*:*,*"] \
+ ipnodes.byname
+
+# Other single maps. No point aliasing
+# audit_user
+# auth_attr
+# exec_attr
+# prof_attr
+# user_attr
+# auto.home
+# auto.master
+# bootparams
+# timezone.byname
+# printers.conf.byname
+# passwd.adjunct.byname
+# group.adjunct.byname
+' >> $MAP_FILE
+
+[ CUST_CMT_NEEDED -eq 1 ] && \
+echo "
+# If any custom map needs to be aliased, then it should be listed
+# here in the following format :
+# nisLDAPdatabaseIdMapping databaseId ":" ["["indexlist"]"] mapname[" "...]
+" >> $MAP_FILE
+
+[ CUST_MAP_NEEDED -eq 1 ] && \
+echo "\
+# Not aliasing non-default/custom maps as they are assumed to be
+# simple, single maps.\
+" >> $MAP_FILE
+
+for MAP in ${ALL_DMN_AUTO_CUST_MAPS[*]} ${ALL_DMN_CUST_MAPS[*]}
+do
+ echo "# $MAP" >> $MAP_FILE
+done
+
+echo "\
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+}
+
+
+#
+# Finds the domains in which the given map exists in the supplied list.
+# Sets result in PRESENT_COUNT and PRESENT_IN_DOMAINS. These fields are
+# set globally, so they can be accessed from any where.
+# Input : $1 - map, $2 - list name (just name, not the value)
+#
+find_domains()
+{
+_MAP=$1
+_ARRAY=$2
+
+let PRESENT_COUNT=0
+PRESENT_IN_DOMAINS=""
+
+let count=0
+
+while (( $count < $N2L_DMN_CNT ))
+do
+
+ # Quick and dirty way to get around unavailability of 2D array
+ case "$_ARRAY" in
+ ALL_MAPS ) _LIST=${ALL_MAPS[$count]} ;;
+ DEF_MAPS ) _LIST=${DEF_MAPS[$count]} ;;
+ CUST_MAPS ) _LIST=${CUST_MAPS[$count]} ;;
+ AUTO_CUST_MAPS ) _LIST=${AUTO_CUST_MAPS[$count]} ;;
+ * ) echo "Invalid value: \"${_ARRAY}\". \c"
+ ;;
+ esac
+
+ if present $_MAP $_LIST
+ then
+ let PRESENT_COUNT="$PRESENT_COUNT + 1"
+ PRESENT_IN_DOMAINS="$PRESENT_IN_DOMAINS ${N2L_DMN_LIST[count]}"
+ fi
+ let count="count + 1"
+done
+
+[ $DEBUG -eq 1 ] && echo "PRESENT_COUNT = $PRESENT_COUNT"
+[ $DEBUG -eq 1 ] && echo "PRESENT_IN_DOMAINS = $PRESENT_IN_DOMAINS"
+
+return 0
+}
+
+
+#
+# For a given map, find out which list it belongs to (PRESENT_IN_LIST),
+# and in how many domains this map shows up (PRESENT_COUNT), and in
+# which ones (PRESENT_IN_DOMAINS). These fields are set globally, so
+# they can be accessed from any where.
+#
+find_map_presence_details()
+{
+_MAP=$1
+
+let PRESENT_COUNT=0
+PRESENT_IN_LIST=""
+PRESENT_IN_DOMAINS=""
+
+# If the map does not exist, return right away, else
+# find which list it belongs to.
+# If a map exists in def or auto or cust lists, then
+# it also exists in "all" list.
+
+if ! present $_MAP $ALL_DMN_ALL_MAPLIST
+then
+ return 1
+
+elif present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ PRESENT_IN_LIST="DEF_MAPS"
+
+elif present $_MAP $ALL_DMN_CUST_MAPLIST
+then
+ PRESENT_IN_LIST="CUST_MAPS"
+
+else
+ # If map exists, and not in previous two lists,
+ # then it has to be here only.
+ PRESENT_IN_LIST="AUTO_CUST_MAPS"
+fi
+
+# Now we know which list the map belongs to. So, we need to
+# find which are the domains in which this map exists.
+
+find_domains $_MAP $PRESENT_IN_LIST
+
+# Since the above function sets the values of PRESENT_COUNT and
+# PRESENT_IN_DOMAINS fields, we don't need to do anything else.
+
+[ $DEBUG -eq 1 ] && echo "PRESENT_IN_LIST = $PRESENT_IN_LIST"
+
+return 0
+}
+
+
+#
+# Check if the comment char is a single character, return 0 on success.
+# Input is passed via global variable "COMMENT_CHAR"
+#
+valid_comment_char()
+{
+COMMENT_CHAR_LENGTH=`echo "${COMMENT_CHAR}" | wc -c`
+
+# echo adds new line character, so adjust length appropriately
+if [ $COMMENT_CHAR_LENGTH -gt 2 ]; then
+ echo " Comment character has to be a blank or single character; try again."
+ return 1
+else
+ return 0
+fi
+}
+
+
+#
+# Read the comment character for a MAP. Append in mapping file if valid.
+# Input - $1 : MAP name
+#
+get_comment_char()
+{
+_MAP=$1
+
+while :
+do
+ get_ans "Specify the comment character for $_MAP :"
+ COMMENT_CHAR=$ANS
+
+ if valid_comment_char; then
+ break
+ fi
+done
+
+echo "nisLDAPcommentChar $_MAP : '${COMMENT_CHAR}'" >> $MAP_FILE
+}
+
+
+#
+# Read a seperate comment character for a MAP for each domain and
+# update this information in mapping file.
+# Input - $1 : MAP name, $@ : list of domains
+#
+get_comment_char_per_domain()
+{
+_MAP=$1
+shift
+_DOMAIN_LIST="$@"
+
+for _DMN in $_DOMAIN_LIST
+do
+
+ while :
+ do
+
+ get_ans "Specify the comment character for $_MAP,${_DMN} :"
+ COMMENT_CHAR=$ANS
+
+ if valid_comment_char; then
+ break
+ fi
+
+ done
+ echo "nisLDAPcommentChar $_MAP,${_DMN} : '${COMMENT_CHAR}'" >> $MAP_FILE
+
+done
+}
+
+
+#
+# This function generates custom comment entries. The output is
+# appended in the mapping file.
+#
+get_custom_nisLDAPcommentChar()
+{
+
+# All the auto mounter maps are assumed to have '#' as the default comment
+# char. But still list the non-default auto map entries here anyway. This
+# will make it very easy in case these entries need to be changed.
+
+for MAP in ${ALL_DMN_AUTO_CUST_MAPS[*]}
+do
+ echo "nisLDAPcommentChar $MAP : '#'" >> $MAP_FILE
+done
+
+if [ CUST_MAP_NEEDED -eq 1 ]; then
+ get_confirm "Do you wish to specify the comment character for any custom map (y/n/h)?" \
+ "n" "custom_map_comment_char_help"
+
+ if [ $? -eq 1 ]; then
+ for MAP in ${ALL_DMN_CUST_MAPS[*]}
+ do
+
+ get_confirm "Do you wish to specify comment character for \"$MAP\" (y/n/h)?" \
+ "n" "custom_map_comment_char_help"
+
+ if [ $? -eq 1 ]; then
+ find_domains $MAP CUST_MAPS
+ if [ $PRESENT_COUNT -gt 1 ]; then
+ echo "Map \"$MAP\" is present in these domains : $PRESENT_IN_DOMAINS"
+
+ get_confirm "For \"$MAP\", should the same comment character be set for all the domains (y/n/h)?" \
+ "y" "same_comment_char_help"
+
+ if [ $? -eq 1 ]; then
+ get_comment_char $MAP
+ else
+ get_comment_char_per_domain $MAP "$PRESENT_IN_DOMAINS"
+ fi
+
+ else
+ get_comment_char $MAP
+ fi
+
+ fi
+ done
+ fi
+fi
+
+}
+
+
+# List comment character (if any) for maps
+create_nisLDAPcommentChar()
+{
+
+echo "\
+# Specify the character representing the start of comments.
+" >> $MAP_FILE
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo "\
+# The comment character represents the start of the special 'comment'
+# field in a given NIS map. If this attribute is not present then the
+# default comment character '#' is used. If a map cannot contain comments
+# then the NULL ('') comment character should be specified. The format to
+# specify the comment character is :
+# nisLDAPcommentChar MAP[,DOMAIN] : 'single_comment_char'
+" >> $MAP_FILE
+
+echo "\
+nisLDAPcommentChar group : ''
+nisLDAPcommentChar passwd : ''
+nisLDAPcommentChar ageing.byname : ''
+nisLDAPcommentChar audit_user : ''
+nisLDAPcommentChar auth_attr : ''
+nisLDAPcommentChar exec_attr : ''
+nisLDAPcommentChar user_attr : ''
+nisLDAPcommentChar bootparams : ''
+" >> $MAP_FILE
+
+# Need to handle passwd.adjunct.byname map for multiple domain.
+_MAP=passwd.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo "#nisLDAPcommentChar passwd.adjunct.byname: ''" >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+ # Don't put domain info as the map is present in all of them.
+ echo "nisLDAPcommentChar passwd.adjunct.byname: ''" >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPcommentChar passwd.adjunct.byname,${_DMN}: ''" >> $MAP_FILE
+ done
+ fi
+fi
+# passwd.adjunct.byname done
+
+
+# Need to handle group.adjunct.byname map for multiple domain.
+_MAP=group.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo "#nisLDAPcommentChar group.adjunct.byname: ''" >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+ # Don't put domain info as the map is present in all of them.
+ echo "nisLDAPcommentChar group.adjunct.byname: ''" >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPcommentChar group.adjunct.byname,${_DMN}: ''" >> $MAP_FILE
+ done
+ fi
+fi
+# group.adjunct.byname done
+
+echo "" >> $MAP_FILE
+
+# Ask user for comment char for custom maps
+get_custom_nisLDAPcommentChar
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+}
+
+
+#
+# Generate secure flag entries
+#
+create_secure_flag_entries()
+{
+echo "\
+# Specify YP_SECURE flags
+" >> $MAP_FILE
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo "\
+# If a map is secure, then it needs to be mentioned here
+# in the following format :
+# nisLDAPmapFlags mapname : s
+">> $MAP_FILE
+
+echo "\
+# nisLDAPmapFlags audit_user : s
+" >> $MAP_FILE
+
+# Need to handle passwd.adjunct.byname map for multiple domain.
+_MAP=passwd.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo "#nisLDAPmapFlags passwd.adjunct.byname : s" >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+ # Don't put domain info as the map is present in all of them.
+ echo "nisLDAPmapFlags passwd.adjunct.byname : s" >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPmapFlags passwd.adjunct.byname,${_DMN} : s" >> $MAP_FILE
+ done
+ fi
+fi
+
+# Need to handle group.adjunct.byname map for multiple domain.
+_MAP=group.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo "#nisLDAPmapFlags group.adjunct.byname : s" >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+ # Don't put domain info as the map is present in all of them.
+ echo "nisLDAPmapFlags group.adjunct.byname : s" >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPmapFlags group.adjunct.byname,${_DMN} : s" >> $MAP_FILE
+ done
+ fi
+fi
+
+echo "" >> $MAP_FILE
+
+STR="any" # Just to make the question look better.
+while :
+do
+ get_confirm "Do you wish to set the secure flag for $STR map (y/n/h)?" \
+ "n" "secure_flag_on_help"
+
+ if [ $? -eq 0 ]; then
+ return 0
+
+ else
+ get_ans "Enter the MAP name :"
+ MAP=$ANS
+
+ if [[ $MAP = "" ]]; then
+ echo " Error : BLANK map name not allowed; try again"
+ continue
+ fi
+
+ # Check if the supplied map name exists, and if yes, then
+ # set the PRESENT attributes for further processing
+
+ find_map_presence_details $MAP
+
+ case $PRESENT_COUNT in
+
+ 0 ) echo " Error : $MAP not found in any domain; try again"
+ ;;
+
+ 1 ) # The map exists in only one domain.
+ echo "nisLDAPmapFlags $MAP : s" >> $MAP_FILE
+ STR="another" # Just to make the question look better.
+ ;;
+
+ * ) # The map exists in multiple domain. Ask if this flag needs
+ # to be set for all domains, or some specific ones.
+
+ echo "Map \"$MAP\" is present in these domains : $PRESENT_IN_DOMAINS"
+ get_confirm "For this map, do you wish to set this flag for all the domains (y/n/h)?" \
+ "y" "secure_flag_all_domains_help"
+
+ if [ $? -eq 1 ]; then
+ echo "nisLDAPmapFlags $MAP : s" >> $MAP_FILE
+ else
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ get_confirm_nodef "Set secure flag for $MAP,${_DMN} (y/n)?"
+
+ if [ $? -eq 1 ]; then
+ echo "nisLDAPmapFlags $MAP,${_DMN} : s" >> $MAP_FILE
+ fi
+
+ done
+ fi
+ STR="another" # Just to make the question look better.
+ ;;
+
+ esac
+
+ fi
+done
+}
+
+
+#
+# Generate interdomain flag entries
+#
+create_interdomain_flag_entries()
+{
+
+INTERDOMAIN_MAP_LIST="ipnodes
+ multiipnodes
+ hosts
+ multihosts
+ services.byservicename"
+
+#
+# Simple function to avoid duplication of code
+#
+print_interdomain_entries()
+{
+for _MAP in $INTERDOMAIN_MAP_LIST
+do
+ echo "nisLDAPmapFlags ${_MAP} : b" >> $MAP_FILE
+done
+}
+
+echo "
+# Specify YP_INTERDOMAIN flags
+" >> $MAP_FILE
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo "\
+# It is used to indicate NIS servers to use the domain name resolver for
+# host name and address lookups for hosts not found in the maps.
+# If set, it adds YP_INTERDOMAIN entries in these maps when converting
+# data from LDAP to YP. It needs to be set in the following format :
+# nisLDAPmapFlags mapname : b
+" >> $MAP_FILE
+
+# List one set of entries in commented form anyway as it might help
+# user understand what it means.
+
+echo "\
+# If \$B is set in /var/yp/Makefile, then this flag should be
+# set for following maps :\
+" >> $MAP_FILE
+
+for _MAP in $INTERDOMAIN_MAP_LIST
+do
+ echo "# nisLDAPmapFlags ${_MAP} : b" >> $MAP_FILE
+done
+
+# Put a blank line for indentation purpose
+echo >> $MAP_FILE
+
+get_confirm "Do you wish to set the \"interdomain\" flag for any domain (y/n/h)?" \
+ "n" "interdomain_flag_on_help"
+
+if [ $? -eq 1 ]; then
+
+ if [ $N2L_DMN_CNT -gt 1 ]; then
+
+ get_confirm "Should \"interdomain\" flag be set for all domain (y/n/h)?" \
+ "y" "interdomain_flag_all_domains_help"
+
+ if [ $? -eq 1 ]; then
+ print_interdomain_entries
+ else
+
+ for _DMN in ${N2L_DMN_LIST[*]}
+ do
+ get_confirm_nodef "Set interdomain flag for ${_DMN} (y/n)?"
+
+ if [ $? -eq 1 ]; then
+ for _MAP in $INTERDOMAIN_MAP_LIST
+ do
+ echo "nisLDAPmapFlags ${_MAP},${_DMN} : b" >> $MAP_FILE
+ done
+ fi
+
+ done
+ fi
+
+ else
+ print_interdomain_entries
+ fi
+fi
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+
+return 0
+}
+
+
+#
+# List SECURE and INTERDOMAIN flags
+#
+create_nisLDAPmapFlags()
+{
+create_secure_flag_entries
+create_interdomain_flag_entries
+}
+
+
+#
+# Print one Map TTL entry in mapping file using supplied TTL.
+#
+print_one_map_ttl_entry()
+{
+_Map=$1
+_iTtlLo=$2
+_iTtlHi=$3
+_runTtl=$4
+
+echo "\
+nisLDAPentryTtl ${_Map}:${_iTtlLo}:${_iTtlHi}:${_runTtl}\
+" >> $MAP_FILE
+
+return 0
+}
+
+
+#
+# Print all the maps TTL entries of same TTL
+# values using the supplied TTL triplet.
+#
+print_all_same_ttl_entries()
+{
+_iTTLlo=$1
+_iTTLhi=$2
+_runTTL=$3
+
+for _MAP in ${DEF_TTL_MAPLIST} ${ALL_DMN_CUST_MAPS[*]} \
+ ${ALL_DMN_AUTO_CUST_MAPS[*]}
+do
+
+ if [ "$_MAP" != "passwd.adjunct.byname" ] && \
+ [ "$_MAP" != "group.adjunct.byname" ]
+ then
+ print_one_map_ttl_entry $_MAP $_iTTLlo $_iTTLhi $_runTTL
+
+ else
+
+ # adjunct maps might not exist in all the domains.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # Don't put domain info as the map is present in all of them.
+ print_one_map_ttl_entry $_MAP $_iTTLlo $_iTTLhi $_runTTL
+
+ else
+
+ for _DMN_ in $PRESENT_IN_DOMAINS
+ do
+ _STR="${_MAP},${_DMN_}"
+ print_one_map_ttl_entry $_STR $_iTTLlo $_iTTLhi $_runTTL
+ done
+
+ fi
+ fi
+done
+
+return 0
+}
+
+#
+# Read the initialTTLlo. Set the value in global variable.
+#
+get_ittl_lo()
+{
+get_pos_int "Lower limit for initial TTL (in seconds) (h=help):" \
+ "$DEF_iTTLlo" "initialTTLlo_help"
+
+iTTLlo=${NUM}
+}
+
+
+#
+# Read the initialTTLhi. Set the value in global variable.
+#
+get_ittl_hi()
+{
+get_pos_int "Higher limit for initial TTL (in seconds) (h=help):" \
+ "$DEF_iTTLhi" "initialTTLhi_help"
+
+iTTLhi=${NUM}
+}
+
+
+#
+# Read the initialTTLhi. Set the value in global variable.
+#
+get_run_ttl()
+{
+get_pos_int "Runtime TTL (in seconds) (h=help):" \
+ "$DEF_runTTL" "runningTTL_help"
+
+runTTL=${NUM}
+}
+
+
+#
+# Read one TTL triplet. Set the result in global variables.
+#
+read_one_ttl_triplet()
+{
+# Just call the individual functions for each TTL.
+
+ get_ittl_lo
+ get_ittl_hi
+ get_run_ttl
+
+[ $DEBUG -eq 1 ] && \
+ echo "TTL = ${iTTLlo}:${iTTLhi}:${runTTL}"
+
+return 0
+}
+
+#
+# Takes MAP name (with or without domain name) as argument, asks
+# user for TTL values, and appends the entry in the mapping file.
+#
+process_one_map_ttl_value()
+{
+
+_Map_="$1"
+
+get_confirm "Retain the default TTL values [$DEF_iTTLlo:$DEF_iTTLhi:$DEF_runTTL] for \"$_Map_\" (y/n/h) ?" \
+ "y" "default_different_ttl_help"
+
+if [ $? -eq 1 ]; then
+ print_one_map_ttl_entry $_Map_ $DEF_iTTLlo $DEF_iTTLhi $DEF_runTTL
+else
+
+ echo "Reading TTL values for $_Map_ :"
+ read_one_ttl_triplet
+ print_one_map_ttl_entry $_Map_ $iTTLlo $iTTLhi $runTTL
+
+fi
+return 0
+}
+
+
+#
+# Read only one TTL triplet for each existing MAP without asking
+# different values for each domain and update the mapping file.
+#
+read_all_maps_ttl_values_no_multiple_domain_issue()
+{
+
+# Need to read only one TTL triplet for each existing MAP.
+
+for _MAP in ${DEF_TTL_MAPLIST} ${ALL_DMN_CUST_MAPS[*]} \
+ ${ALL_DMN_AUTO_CUST_MAPS[*]}
+do
+
+ if [ "$_MAP" != "passwd.adjunct.byname" ] && \
+ [ "$_MAP" != "group.adjunct.byname" ]
+ then
+ process_one_map_ttl_value $_MAP
+
+ else
+
+ # adjunct maps might not exist in all the domains.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # Don't put domain info as the map is present in all of them.
+ process_one_map_ttl_value $_MAP
+
+ else
+
+ for _DMN_ in $PRESENT_IN_DOMAINS
+ do
+ _STR="${_MAP},${_DMN_}"
+ process_one_map_ttl_value $_STR
+ done
+
+ fi
+ fi
+done
+
+return 0
+}
+
+
+#
+# Read TTL triplet for each default MAP (in database ID form) while
+# taking care of multiple domains issue and update the mapping file.
+#
+read_default_maps_ttl_values_with_multi_domain_issue()
+{
+
+for _MAP_ in ${DEF_TTL_MAPLIST}
+do
+ if [ "$_MAP_" != "passwd.adjunct.byname" ] && \
+ [ "$_MAP_" != "group.adjunct.byname" ]
+ then
+
+ for _DMN_ in ${N2L_DMN_LIST[*]}
+ do
+ _STR_="${_MAP_},${_DMN_}"
+ # Now process each combination one at a time.
+ process_one_map_ttl_value "$_STR_"
+ done
+
+ else
+ # List only those domains in which adjunct.byname exists.
+ find_domains $_MAP_ DEF_MAPS
+ for _DMN_ in $PRESENT_IN_DOMAINS
+ do
+ _STR_="${_MAP_},${_DMN_}"
+ process_one_map_ttl_value "$_STR_"
+ done
+ fi
+done
+
+return 0
+}
+
+
+#
+# Read TTL triplet for each existing custom MAP while taking
+# care of multiple domains issue and update the mapping file.
+#
+read_custom_maps_ttl_values_with_multi_domain_issue()
+{
+
+for _MAP_ in ${ALL_DMN_CUST_MAPS[*]} ${ALL_DMN_AUTO_CUST_MAPS[*]}
+do
+
+ find_map_presence_details $_MAP_
+
+ if [ $PRESENT_COUNT -eq 1 ]; then
+
+ # This map exists in only one domain.
+ # So, no need to ask for multiple domains.
+
+ process_one_map_ttl_value $_MAP_
+
+ else
+
+ # Handle multiple domains.
+
+ echo "Map \"${_MAP_}\" is present in these domains : $PRESENT_IN_DOMAINS"
+
+ get_confirm "For this map, do you wish to use the same TTL values for all the domains (y/n/h) ?" \
+ "y" "same_ttl_across_domains_help"
+
+ if [ $? -eq 1 ]; then
+
+ # Need to read only one TTL triplet for this MAP.
+ process_one_map_ttl_value $_MAP_
+
+ else
+
+ # Need to ask for each domain
+
+ for _DMN_ in $PRESENT_IN_DOMAINS
+ do
+ _STR="${_MAP_},${_DMN_}"
+
+ # Now process each combination one at a time.
+ process_one_map_ttl_value "$_STR"
+
+ done
+ fi
+ fi
+done
+
+return 0
+}
+
+
+#
+# List the TTL values for various MAPs
+#
+create_nisLDAPentryTtl()
+{
+
+echo "\
+# Associate TTLs with NIS entries derived from LDAP
+" >> $MAP_FILE
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo "\
+# Each map has three TTL values which are specified in seconds.
+# 1. initialTTLlo (default $DEF_iTTLlo sec) The lower limit for the initial
+# TTL (in seconds) for data read from disk when the ypserv starts.
+#
+# 2. initialTTLhi (default $DEF_iTTLhi sec) The upper limit for initial TTL.
+#
+# 3. runningTTL (default $DEF_runTTL sec) The TTL (in seconds) for data
+# retrieved from LDAP while the ypserv is running.
+#
+# If any value is not specified, then default value is used.
+# The format of TTL entry is :
+# nisLDAPentryTtl MAP[,DOMAIN]:initialTTLlo:initialTTLhi:runningTTL
+" >> $MAP_FILE
+
+# If no maps are present, just return.
+[ ${#ALL_DMN_ALL_MAPS[*]} -eq 0 ] && return 0
+
+echo "The default TTL for each map is set to ${DEF_iTTLlo}:${DEF_iTTLhi}:${DEF_runTTL}"
+get_confirm "Do you wish to change the TTL values for any map (y/n/h) ?" \
+ "n" "default_ttl_help"
+
+if [ $? -eq 0 ]; then
+ # Default values accepted for all the maps.
+ # So, just print all the maps with default TTL values.
+
+ print_all_same_ttl_entries $DEF_iTTLlo $DEF_iTTLhi $DEF_runTTL
+
+else
+ echo "You would be allowed to enter the new TTL values."
+ get_confirm "Do you wish to use the same TTL values for all the maps (y/n/h) ?" \
+ "y" "non_default_same_ttl_help"
+
+ if [ $? -eq 1 ]; then
+ # Need to read only one TTL triplet.
+ # Print all the maps with new TTL triplet.
+
+ # read one ttl triplet
+ echo "Enter the new TTL values :"
+
+ read_one_ttl_triplet
+
+ print_all_same_ttl_entries $iTTLlo $iTTLhi $runTTL
+
+ else
+ if [ $N2L_DMN_CNT -eq 1 ]; then
+
+ # TTL values are different now. But we haev only one domain.
+ # So, no need to worry about multiple domains. Need to read
+ # only one TTL triplet for each existing MAP.
+
+ read_all_maps_ttl_values_no_multiple_domain_issue
+
+ else
+
+ # TTL values are different now. And we have multiple domains
+ # too. Check if MAPS are going to have same TTL across domains.
+ # This is just to avoid asking too many TTL triplet inputs
+
+ echo "You would be allowed to enter different TTL values for each map."
+
+ get_confirm "For a given map, do you wish to use the same TTL values for all the domains (y/n/h) ?" \
+ "y" "non_default_different_ttl_help"
+
+ if [ $? -eq 1 ]; then
+
+ # Need to read only one TTL triplet for each existing MAP.
+ read_all_maps_ttl_values_no_multiple_domain_issue
+
+ else
+
+ # We have hit the worst case scenario. TTLs could be
+ # different per map and per domain.
+
+ read_default_maps_ttl_values_with_multi_domain_issue
+ read_custom_maps_ttl_values_with_multi_domain_issue
+ fi
+ fi
+ fi
+fi
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+
+return 0
+}
+
+
+#
+# The custom maps for which we do not have enough
+# information to be able to generate specific entries,
+# we just log the message that the user needs to take
+# care of those entries manually.
+#
+ask_user_to_update_the_custom_map_entries_too()
+{
+
+if [ ${#ALL_DMN_CUST_MAPS[*]} -gt 0 ]; then
+
+ echo "
+# Similar entries need to be created
+# for following custom maps too :\
+" >> $MAP_FILE
+
+ for _MAP in ${ALL_DMN_CUST_MAPS[*]}
+ do
+ echo "# $_MAP" >> $MAP_FILE
+ done
+fi
+}
+
+
+put_default_nisLDAPnameFields()
+{
+echo '
+# Associate names with fields in the maps. Must be same for all domains.
+nisLDAPnameFields audit_user: \
+ ("%s:%s:%s", name, alwaysAuditFlags, neverAuditFlags)
+
+nisLDAPnameFields auto.home: \
+ ("%s",value)
+
+nisLDAPnameFields auto.master: \
+ ("%s",value)
+
+nisLDAPnameFields auth_attr: \
+ ("%s:%s:%s:%s:%s:%s", \
+ name, res1, res2, short_desc, long_desc, attrs )
+
+nisLDAPnameFields bootparams: \
+ ("%s", params)
+
+nisLDAPnameFields ethers: \
+ ("%s %s", addr, name)
+
+nisLDAPnameFields exec_attr: \
+ ("%s:%s:%s:%s:%s:%s:%s", \
+ name, policy, type, res1, res2, id, attrs)
+
+nisLDAPnameFields group: \
+ ("%s:%s:%s:%s", name, passwd, gid, users)
+' >> $MAP_FILE
+
+# Need to handle group.adjunct.byname map for multiple domain.
+
+_MAP=group.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo '#nisLDAPnameFields group.adjunct.byname: \
+# ("%s:%s", name, passwd)
+' >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # Don't put domain info as the map is present in all of them.
+ echo 'nisLDAPnameFields group.adjunct.byname: \
+ ("%s:%s", name, passwd)
+' >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPnameFields group.adjunct.byname,${_DMN}: \\
+ (\"%s:%s\", name, passwd)
+" >> $MAP_FILE
+ done
+ fi
+fi
+
+echo 'nisLDAPnameFields keys.host: \
+ ("%s:%s", publicKey ,secretKey)
+
+nisLDAPnameFields keys.pass: \
+ ("%s:%s", publicKey ,secretKey)
+
+nisLDAPnameFields keys.nobody: \
+ ("%s:%s", publicKey ,secretKey)
+
+nisLDAPnameFields hosts: \
+ ("%a %s %s", addr, canonicalName, aliases)
+
+nisLDAPnameFields multihosts: \
+ ("%a %s %s", addr, canonicalName, aliases)
+
+nisLDAPnameFields ipnodes: \
+ ("%a %s %s", addr, canonicalName, aliases)
+
+nisLDAPnameFields multiipnodes: \
+ ("%a %s %s", addr, canonicalName, aliases)
+
+nisLDAPnameFields mail.aliases: \
+ ("%s", addresses)
+
+nisLDAPnameFields mail.mapping: \
+ ("%s", address)
+
+# memberTriples is split into sub-fields by a latter nisLDAPsplitField
+# attribute.
+nisLDAPnameFields netgroup: \
+ ("%s", memberTriples)
+
+nisLDAPnameFields netid.host: \
+ ("%s:%s", number, data)
+
+nisLDAPnameFields netid.pass: \
+ ("%s:%s", number, data)
+
+nisLDAPnameFields netmasks.byaddr: \
+ ("%a", mask)
+
+nisLDAPnameFields networks: \
+ ("%s %s %s", name, number, aliases)
+
+nisLDAPnameFields project: \
+ ("%s:%s:%s:%s:%s:%s", \
+ name, projID, comment, users, groups, attrs)
+
+nisLDAPnameFields protocols: \
+ ("%s %s %s", name, number, aliases)
+
+nisLDAPnameFields rpc.bynumber: \
+ ("%s %s %s", name, number, aliases)
+
+nisLDAPnameFields passwd: \
+ ("%s:%s:%s:%s:%s:%s:%s", \
+ name, passwd, uid, gid, gecos, home, shell)
+
+# It is not obvious what the fields in passwd.adjunct are for. They are not
+# the same as the shadow map. The following is based on information in:-
+#
+# lib/libbc/inc/include/pwdadj.h.
+#
+# This file implies that these are documented in getpwaent(3) but this man page
+# does not seem to exist.
+#
+# It is believed that 'min','max' and 'def' labels were reserved fields in
+# SunOS 4.x and are now unused. 'always' and 'never' audit information is
+# now contained in audit_user(4) so is now unused.
+#
+' >> $MAP_FILE
+
+# Need to handle passwd.adjunct.byname map for multiple domain.
+
+_MAP=passwd.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo '#nisLDAPnameFields passwd.adjunct.byname: \
+# ("%s:%s:%s:%s:%s:%s:%s", \
+# name, passwd, min, max, def, always, \
+# never)
+' >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # Don't put domain info as the map is present in all of them.
+ echo 'nisLDAPnameFields passwd.adjunct.byname: \
+ ("%s:%s:%s:%s:%s:%s:%s", \
+ name, passwd, min, max, def, always, \
+ never)
+' >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPnameFields passwd.adjunct.byname,${_DMN}: \\
+ (\"%s:%s:%s:%s:%s:%s:%s\", \\
+ name, passwd, min, max, def, always, \\
+ never)
+" >> $MAP_FILE
+ done
+ fi
+fi
+
+echo '
+nisLDAPnameFields printers.conf.byname: \
+ ("%s:%s", names, values)
+
+nisLDAPnameFields prof_attr: \
+ ("%s:%s:%s:%s:%s", \
+ name, res1, res2, desc, attrs)
+
+nisLDAPnameFields services: \
+ ("%s %s/%s %s", name, port, protocol, aliases)
+
+# This map is never created but yppasswd uses the mapping to extract password
+# ageing information from the DIT. The password itself is not required by this
+# mechanism so is not included in the ageing mapping.
+nisLDAPnameFields ageing.byname: \
+ ("%s:%s:%s:%s:%s:%s:%s:%s", \
+ name, lastchg, min, max, warn, inactive, \
+ expire, flag)
+
+nisLDAPnameFields timezone.byname: \
+ ("%s %s", zoneName, hostName)
+
+nisLDAPnameFields user_attr: \
+ ("%s:%s:%s:%s:%s", user, qualifier, res1, res2, attrs)
+' >> $MAP_FILE
+}
+
+#
+# List namefields for non-default auto maps and custom maps.
+#
+put_auto_and_custom_map_nisLDAPnameFields()
+{
+for _MAP in ${ALL_DMN_AUTO_CUST_MAPS[*]} ${ALL_DMN_CUST_MAPS[*]}
+do
+
+ echo "\
+nisLDAPnameFields ${_MAP}: \\
+ (\"%s\",value)
+" >> $MAP_FILE
+
+done
+}
+
+
+create_nisLDAPnameFields()
+{
+# Put format information of "nisLDAPnameFields"
+[ CUST_CMT_NEEDED -eq 1 ] && echo '
+# "nisLDAPnameFields" specifies the content of entries in a NIS map
+# and how they should be broken into named fields. It is required as,
+# unlike NIS+, NIS maps do not store information in named fields.
+#
+# Following is the syntax for nisLDAPnameFields :
+#
+# "nisLDAPnameFields" mapName ":" "(" matchspec "," fieldNames ")"
+# fieldName = nameOrArrayName[","...]
+# nameOrArrayName = Name of field or 'array' of repeated fields.
+# matchspec = \" formatString \"
+' >> $MAP_FILE
+
+# List the default nameField values
+put_default_nisLDAPnameFields
+
+# List the underlying assumption
+echo "\
+# With the assumption that all the custom maps are simple, single
+# map (single key-value pair type), below is the nisLDAPnameFields
+# information for all the custom and non-default auto.* maps. If
+# this assumption is not valid, then refer to the NISLDAPmapping
+# man page for information on how to customize this section.
+" >> $MAP_FILE
+
+# List namefields for non-default auto maps and custom maps.
+put_auto_and_custom_map_nisLDAPnameFields
+
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+
+return 0
+}
+
+
+#
+# List repeated field seperators
+#
+create_nisLDAPrepeatedFieldSeparators()
+{
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo "
+# nisLDAPrepeatedFieldSeparators : It is a character which separates
+# the repeatable instnaces of splitable fields. It's format is :
+#
+# nisLDAPrepeatedFieldSeparators fieldName \"sepChar[...]\"
+# sepChar = A separator character.
+# Default value is space or tab.
+" >> $MAP_FILE
+
+echo "\
+#nisLDAPrepeatedFieldSeparators memberTriples: \" \t\"
+" >> $MAP_FILE
+
+}
+
+
+#
+# List split fields
+#
+create_nisLDAPsplitField()
+{
+# List the default split fields
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo '
+# nisLDAPsplitFields : It defines how a field, or list of fields,
+# named by nisLDAPnameFields is split into sub fields. The original
+# field is compared with each line of this attribute until one matches.
+# When a match is found named sub-fields are generated. In latter
+# operations sub-field names can be used in the same way as other
+# field names. The format of nisLDAPsplitFields is :
+#
+# "nisLDAPsplitFields" fieldName ":" splitSpec[","...]
+# splitSpec = "(" matchspec "," subFieldNames ")"
+# fieldName = Name of a field from nisLDAPnameFields
+# subFieldNames = subFieldname[","...]
+# matchspec = \" formatString \"
+' >> $MAP_FILE
+
+echo '
+nisLDAPsplitField memberTriples: \
+ ("(%s,%s,%s)", host, user, domain), \
+ ("%s", group)
+' >> $MAP_FILE
+
+}
+
+#
+# List split fields and repeated field separators.
+#
+create_split_field_and_repeatedfield_seperators()
+{
+
+echo "\
+# Specify how to break fields up into sub fields.
+" >> $MAP_FILE
+
+create_nisLDAPrepeatedFieldSeparators
+
+create_nisLDAPsplitField
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+}
+
+list_default_nisLDAPobjectDN()
+{
+echo '
+# Associate maps with RDNs and object classes. Base DN comes from the
+# nisLDAPdomainContext.
+#
+# As supplied this file gives only the most derived objectClass for each map.
+# For some servers it may be necessary to add "objectClass=" statements for
+# all the superclasses. This should be done here.
+
+nisLDAPobjectDN auto.home: \
+ automountmapname=auto_home,?one? \
+ objectClass=automount:
+
+nisLDAPobjectDN auto.master: \
+ automountmapname=auto_master,?one? \
+ objectClass=automount:
+
+nisLDAPobjectDN auth_attr: \
+ ou=SolarisAuthAttr,?one? \
+ objectClass=SolarisAuthAttr:
+
+nisLDAPobjectDN bootparams: \
+ ou=ethers,?one? \
+ objectClass=bootableDevice, \
+ bootParameter=*:\
+ ou=ethers,?one? \
+ objectClass=device, \
+ objectClass=bootableDevice
+
+
+nisLDAPobjectDN exec_attr:\
+ ou=SolarisProfAttr,?one?objectClass=SolarisExecAttr,\
+ SolarisKernelSecurityPolicy=*:\
+ ou=SolarisProfAttr,?one?objectClass=SolarisExecAttr,\
+ objectClass=SolarisProfAttr,\
+ objectClass=top
+
+nisLDAPobjectDN ethers: \
+ ou=ethers,?one? \
+ objectClass=ieee802Device, \
+ macAddress=*:\
+ ou=ethers,?one? \
+ objectClass=device, \
+ objectClass=ieee802Device
+
+nisLDAPobjectDN group: \
+ ou=group,?one? \
+ objectClass=posixGroup:
+' >> $MAP_FILE
+
+
+# Need to handle group.adjunct.byname map for multiple domain.
+
+_MAP=group.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo '#nisLDAPobjectDN group.adjunct.byname: \
+# ou=group,?one? \
+# objectClass=posixGroup:
+' >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+ # Don't put domain info as the map is present in all of them.
+ echo 'nisLDAPobjectDN group.adjunct.byname: \
+ ou=group,?one? \
+ objectClass=posixGroup:
+' >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPobjectDN group.adjunct.byname,${_DMN}: \\
+ ou=group,?one? \\
+ objectClass=posixGroup:
+" >> $MAP_FILE
+ done
+ fi
+fi
+
+
+echo 'nisLDAPobjectDN hosts: \
+ ou=hosts,?one? \
+ objectClass=ipHost:\
+ ou=hosts,?one? \
+ objectClass=device, \
+ objectClass=ipHost
+
+nisLDAPobjectDN multihosts: \
+ ou=hosts,?one? \
+ objectClass=ipHost, \
+ ipHostNumber=*.*
+
+nisLDAPobjectDN ipnodes: \
+ ou=hosts,?one? \
+ objectClass=ipHost:\
+ ou=hosts,?one? \
+ objectClass=device, \
+ objectClass=ipHost
+
+nisLDAPobjectDN multiipnodes: \
+ ou=hosts,?one? \
+ objectClass=ipHost, \
+ ipHostNumber=*\:*
+
+nisLDAPobjectDN mail.aliases: \
+ ou=aliases,?one? \
+ objectClass=mailGroup:
+
+nisLDAPobjectDN mail.mapping: \
+ ou=aliases,?one? \
+ objectClass=mailGroup
+
+nisLDAPobjectDN netgroup: \
+ ou=netgroup,?one? \
+ objectClass=nisNetgroup:
+
+nisLDAPobjectDN networks: \
+ ou=networks,?one? \
+ objectClass=ipNetwork, \
+ cn=*:
+
+# Must come after networks (or equivalent) that creates ipNetworks
+nisLDAPobjectDN netmasks.byaddr: \
+ ou=networks,?one? \
+ objectClass=ipNetwork, \
+ ipNetMaskNumber=*:
+
+nisLDAPobjectDN passwd: \
+ ou=people,?one? \
+ objectClass=posixAccount:\
+ ou=people,?one? \
+ objectClass=account, \
+ objectClass=shadowAccount, \
+ objectClass=posixAccount
+' >> $MAP_FILE
+
+
+# Need to handle passwd.adjunct.byname map for multiple domain.
+
+_MAP=passwd.adjunct.byname
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+ # Just put the syntax in comment form
+ echo '#nisLDAPobjectDN passwd.adjunct.byname: \
+# ou=people,?one? \
+# objectClass=posixAccount:\
+# ou=people,?one? \
+# objectClass=account, \
+# objectClass=shadowAccount, \
+# objectClass=posixAccount
+' >> $MAP_FILE
+else
+ # Find the domains in which this map exists.
+ find_domains $_MAP DEF_MAPS
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+ # Don't put domain info as the map is present in all of them.
+ echo 'nisLDAPobjectDN passwd.adjunct.byname: \
+ ou=people,?one? \
+ objectClass=posixAccount:\
+ ou=people,?one? \
+ objectClass=account, \
+ objectClass=shadowAccount, \
+ objectClass=posixAccount
+' >> $MAP_FILE
+ else
+ # Not every domain has this map. So, list for the ones which do.
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+ echo "nisLDAPobjectDN passwd.adjunct.byname,${_DMN}: \\
+ ou=people,?one? \\
+ objectClass=posixAccount:\\
+ ou=people,?one? \\
+ objectClass=account, \\
+ objectClass=shadowAccount, \\
+ objectClass=posixAccount
+" >> $MAP_FILE
+ done
+ fi
+fi
+
+
+echo '# Must follow passwd
+nisLDAPobjectDN netid.pass: \
+ ou=people,?one? \
+ objectClass=posixAccount
+
+# Must follow hosts
+nisLDAPobjectDN netid.host: \
+ ou=hosts,?one? \
+ objectClass=ipHost
+
+nisLDAPobjectDN printers.conf.byname: \
+ ou=printers,?one? \
+ objectClass=printerService:\
+ ou=printers,?one? \
+ objectClass=sunPrinter, \
+ objectClass=printerService, \
+ objectClass=printerLPR, \
+ objectClass=printerAbstract
+
+nisLDAPobjectDN prof_attr:\
+ ou=SolarisProfAttr,?one?objectClass=SolarisProfAttr,\
+ SolarisAttrLongDesc=*:\
+ ou=SolarisProfAttr,?one?objectClass=SolarisProfAttr,\
+ objectClass=SolarisExecAttr,\
+ objectClass=top
+nisLDAPobjectDN project: \
+ ou=project,?one? \
+ objectClass=SolarisProject:
+
+nisLDAPobjectDN protocols: \
+ ou=protocols,?one? \
+ objectClass=ipProtocol:
+
+nisLDAPobjectDN rpc.bynumber: \
+ ou=rpc,?one? \
+ objectClass=oncRpc:
+
+nisLDAPobjectDN services.byname: \
+ ou=services,?one? \
+ objectClass=ipService:
+
+# Because services.byservicename contains keys of form both 'name'
+# and 'name/protocol' we generate the DIT just from services.byname.
+# Hence, write-disabled for services.byservicename
+nisLDAPobjectDN services.byservicename: \
+ ou=services,?one? \
+ objectClass=ipService
+
+# This map is never created but yppasswd uses the mapping to extract password
+# aging information from the DIT.
+nisLDAPobjectDN ageing.byname: \
+ ou=people,?one? \
+ objectClass=shadowAccount:
+
+# Using nisplusTimeZoneData objectClass for compatibility with nis+2ldap
+nisLDAPobjectDN timezone.byname: \
+ ou=Timezone,?one? \
+ objectClass=nisplusTimeZoneData:
+
+nisLDAPobjectDN user_attr: \
+ ou=people,?one? \
+ objectClass=SolarisUserAttr:
+
+# Must come after passwd (or equivalent) that creates posixAccounts
+nisLDAPobjectDN audit_user: \
+ ou=people,?one? \
+ objectClass=SolarisAuditUser:
+
+# Must come after hosts + passwd.
+nisLDAPobjectDN keys.host: \
+ ou=hosts,?one? \
+ objectClass=NisKeyObject:
+
+nisLDAPobjectDN keys.pass: \
+ ou=people,?one? \
+ objectClass=NisKeyObject:
+
+nisLDAPobjectDN keys.nobody: \
+ ou=people,?one? \
+ objectClass=NisKeyObject:\
+ ou=people,?one? \
+ objectClass=account, \
+ objectClass=NisKeyObject
+
+nisLDAPobjectDN ypservers: \
+ ou=ypservers,?one? \
+ objectClass=device:
+' >> $MAP_FILE
+}
+
+# List all the non-default auto.* and custom maps.
+list_auto_custom_nisLDAPobjectDN()
+{
+
+# auto.* entries are easy.
+if [ ${#ALL_DMN_AUTO_CUST_MAPS[*]} -gt 0 ]; then
+ echo "# Non-default custom auto maps (auto.*)\n" >> $MAP_FILE
+
+ for _MAP in ${ALL_DMN_AUTO_CUST_MAPS[*]}
+ do
+
+ # We need to find one container for each auto.* map.
+ # Assume that each auto.* maps's container is auto_*.
+
+ _MAP_UNDERSCORE=`echo $_MAP | sed "s/auto\./auto_/"`
+
+ echo "\
+nisLDAPobjectDN ${_MAP}: \\
+ automountmapname=${_MAP_UNDERSCORE},?one? \\
+ objectClass=automount:
+" >> $MAP_FILE
+ done
+fi
+
+# Since we do not have enough information to generate
+# entries for other custom maps, best we can do is to
+# log this map names and ask user to take care of them.
+
+ask_user_to_update_the_custom_map_entries_too
+
+}
+
+
+#
+# List association of maps with RDNs and object classes.
+#
+create_nisLDAPobjectDN()
+{
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo '
+# nisLDAPobjectDN : It specifies the connection between group of NIS
+# maps and the LDAP directory. This attribute also defines the 'order'
+# of the NIS maps. When NIS maps are bulk copied to or from the DIT
+# they are processed in the same order as related nisLDAPobjectDN
+# attributes appear in /var/yp/NISLDAPmapping.
+# The format of "nisLDAPobjectDN" is :
+#
+# mapName[" "...] ":" objectDN *( ";" objectDN )
+#
+# where:
+#
+# objectDN = readObjectSpec [":"[writeObjectSpec]]
+# readObjectSpec = [baseAndScope [filterAttrValList]]
+# writeObjectSpec = [baseAndScope [attrValList]]
+# baseAndScope = [baseDN] ["?" [scope]]
+# filterAttrValList = ["?" [filter | attrValList]]]
+# scope = "base" | "one" | "sub"
+# attrValList = attribute "=" value
+# *("," attribute "=" value)
+' >> $MAP_FILE
+
+# List all the default entries anyway.
+list_default_nisLDAPobjectDN
+
+# List all the non-default auto.* and custom maps.
+list_auto_custom_nisLDAPobjectDN
+
+}
+
+#
+# List all the default nisLDAPattributeFromField entries
+#
+list_default_nisLDAPattributeFromField()
+{
+echo '
+# Describe how named fields are mapped to DIT entries.
+
+# audit_user
+nisLDAPattributeFromField audit_user: \
+ dn=("uid=%s,", rf_key ), \
+ SolarisAuditAlways=alwaysAuditFlags, \
+ SolarisAuditNever=neverAuditFlags
+
+# auto.home
+nisLDAPattributeFromField auto.home: \
+ dn=("automountKey=%s,", rf_key ), \
+ automountKey=rf_key, \
+ automountInformation=value
+
+# auto.master
+nisLDAPattributeFromField auto.master: \
+ dn=("automountKey=%s,", rf_key ), \
+ automountKey=rf_key, \
+ automountInformation=value
+
+# auth_attr
+nisLDAPattributeFromField auth_attr: \
+ dn=("cn=%s,", rf_key ), \
+ cn=name, \
+ SolarisAttrReserved1=res1, \
+ SolarisAttrReserved2=res2, \
+ SolarisAttrShortDesc=short_desc, \
+ SolarisAttrLongDesc=long_desc, \
+ SolarisAttrKeyValue=attrs
+
+# exec_attr. Because of the messy NIS keys special handling is required here
+nisLDAPattributeFromField exec_attr: \
+ dn=("cn=%s+SolarisKernelSecurityPolicy=%s\
+ +SolarisProfileType=%s+SolarisProfileID=%s,", \
+ name, policy,type,id), \
+ ("%s:*", cn)=rf_key, \
+ ("*:%s:*", SolarisKernelSecurityPolicy)=rf_key, \
+ ("*:*:%s", SolarisProfileId)=rf_key, \
+ solarisProfileType=type, \
+ solarisAttrReserved1=res1, \
+ SolarisAttrReserved2=res2, \
+ solarisAttrKeyValue=attrs
+
+# ethers
+nisLDAPattributeFromField ethers.byname: \
+ dn=("cn=%s,", rf_key ), \
+ macAddress=addr
+nisLDAPattributeFromField ethers.byaddr: \
+ dn=("cn=%s,", name ), \
+ macAddress=rf_key
+nisLDAPattributeFromField ethers: \
+ cn=name, \
+ description=rf_comment
+
+# bootparams. Must be done after ethers
+nisLDAPattributeFromField bootparams: \
+ dn=("cn=%s,", rf_key ), \
+ cn=rf_key, \
+ (bootParameter)=(params, " ")
+' >> $MAP_FILE
+
+# group syntax is different when group.adjunct map is present.
+# So, need to handle the various possibilities
+
+_MAP=group.adjunct.byname
+
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+
+ # Just put the group.adjunct syntax in comment form
+
+ echo '# group
+nisLDAPattributeFromField group.byname: \
+ dn=("cn=%s,", rf_key ), \
+ gidNumber=gid
+nisLDAPattributeFromField group.bygid: \
+ dn=("cn=%s,", name ), \
+ gidNumber=rf_key
+nisLDAPattributeFromField group: \
+ cn=name, \
+ userPassword=("{crypt}%s",passwd), \
+ (memberUid)=(users, ",")
+
+#
+# If you are using group.adjunct, comment the group section above
+# and uncomment the following group and group.adjunct sections
+#
+# group
+#nisLDAPattributeFromField group.byname: \
+# dn=("cn=%s,", rf_key ), \
+# gidNumber=gid
+#nisLDAPattributeFromField group.bygid: \
+# dn=("cn=%s,", name ), \
+# gidNumber=rf_key
+#nisLDAPattributeFromField group: \
+# cn=name, \
+# (memberUid)=(users, ",")
+
+# group.adjunct
+#nisLDAPattributeFromField group.adjunct.byname: \
+# dn=("cn=%s,", rf_key ), \
+# cn=name, \
+# userPassword=("{crypt}%s",passwd)
+' >> $MAP_FILE
+
+else
+
+ # Find the domains in which group.adjunct map exists.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # All the domains have group.adjunct map.
+
+ echo '# group
+#nisLDAPattributeFromField group.byname: \
+# dn=("cn=%s,", rf_key ), \
+# gidNumber=gid
+#nisLDAPattributeFromField group.bygid: \
+# dn=("cn=%s,", name ), \
+# gidNumber=rf_key
+#nisLDAPattributeFromField group: \
+# cn=name, \
+# userPassword=("{crypt}%s",passwd), \
+# (memberUid)=(users, ",")
+
+# If you are not using group.adjunct, uncomment the group section above
+# and comment the following group and group.adjunct sections
+#
+# group
+nisLDAPattributeFromField group.byname: \
+ dn=("cn=%s,", rf_key ), \
+ gidNumber=gid
+nisLDAPattributeFromField group.bygid: \
+ dn=("cn=%s,", name ), \
+ gidNumber=rf_key
+nisLDAPattributeFromField group: \
+ cn=name, \
+ (memberUid)=(users, ",")
+
+# group.adjunct
+nisLDAPattributeFromField group.adjunct.byname: \
+ dn=("cn=%s,", rf_key ), \
+ cn=name, \
+ userPassword=("{crypt}%s",passwd)
+' >> $MAP_FILE
+
+ else
+ # Not every domain has group.adjunct map.
+
+ # First put the password syntax with domain name for domains
+ # in which group.adjunct exists.
+
+ echo "# group" >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+# domain-specific group
+nisLDAPattributeFromField group.byname,${_DMN}: \\
+ dn=(\"cn=%s,\", rf_key ), \\
+ gidNumber=gid
+nisLDAPattributeFromField group.bygid,${_DMN}: \\
+ dn=(\"cn=%s,\", name ), \\
+ gidNumber=rf_key
+nisLDAPattributeFromField group,${_DMN}: \\
+ cn=name, \\
+ (memberUid)=(users, \",\")
+" >> $MAP_FILE
+ done
+
+ # Now put the other group syntax. We do not need to
+ # append the domain name here.
+
+ echo '
+nisLDAPattributeFromField group.byname: \
+ dn=("cn=%s,", rf_key ), \
+ gidNumber=gid
+nisLDAPattributeFromField group.bygid: \
+ dn=("cn=%s,", name ), \
+ gidNumber=rf_key
+nisLDAPattributeFromField group: \
+ cn=name, \
+ userPassword=("{crypt}%s",passwd), \
+ (memberUid)=(users, ",")
+' >> $MAP_FILE
+
+ # Now we need to put the group.adjunct syntax for domains
+ # in which this map exists.
+
+ echo "# group.adjunct" >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPattributeFromField group.adjunct.byname,${_DMN}: \\
+ dn=(\"cn=%s,\", rf_key ), \\
+ cn=name, \\
+ userPassword=(\"{crypt}%s\",passwd)
+" >> $MAP_FILE
+ done
+
+ fi
+
+fi
+
+
+echo '
+# hosts
+# Cannot forward map hosts.byname key as the YP_MULTI entries will not work.
+nisLDAPattributeFromField hosts.byname: \
+ cn=rf_searchkey
+nisLDAPattributeFromField hosts.byaddr: \
+ ipHostNumber=rf_searchipkey
+nisLDAPattributeFromField hosts: \
+ ipHostNumber=addr, \
+ dn=("cn=%s+ipHostNumber=%s,", canonicalName, addr), \
+ cn=canonicalName, \
+ (cn)=(aliases, " "), \
+ description=rf_comment
+
+nisLDAPattributeFromField multihosts: \
+ ("YP_MULTI_%s", cn)=rf_searchkey
+
+# ipnodes
+# Cannot forward map ipnodes.byname key as the YP_MULTI entries will not work.
+nisLDAPattributeFromField ipnodes.byname: \
+ cn=rf_searchkey
+nisLDAPattributeFromField ipnodes.byaddr: \
+ ipHostNumber=rf_searchipkey
+nisLDAPattributeFromField ipnodes: \
+ ipHostNumber=addr, \
+ dn=("cn=%s+ipHostNumber=%s,", canonicalName, addr), \
+ cn=canonicalName, \
+ (cn)=(aliases, " "), \
+ description=rf_comment
+
+nisLDAPattributeFromField multiipnodes: \
+ ("YP_MULTI_%s", cn)=rf_searchkey
+
+#mail.aliases
+nisLDAPattributeFromField mail.aliases: \
+ dn=("mail=%s,", rf_key), \
+ mail=rf_key, \
+ (mgrprfc822mailmember)=(addresses, ",")
+
+#mail.mapping
+#Commented out because all NIS->LDAP mappings are done by mail.aliases
+#nisLDAPattributeFromField mail.mapping: \
+# dn=("mail=%s,", address), \
+# mail=address, \
+# mgrprfc822mailmember=rf_key
+nisLDAPattributeFromField mail.mapping: \
+ mgrprfc822mailmember=rf_searchkey
+
+# netgroup.
+#
+# Only need to create DIT entries for netgroup. This contains a superset of
+# the information in netgroup.byhost and netgroup.byuser
+nisLDAPattributeFromField netgroup: \
+ dn=("cn=%s,", rf_key ), \
+ (memberNisNetgroup)=group, \
+ (nisNetgroupTriple)= \
+ ("(%s,%s,%s)", host, user, domain), \
+ cn=rf_key, \
+ description=rf_comment
+
+# netid.pass
+#
+# Commented out because, unless remote domains (and thus /etc/netid) is
+# supported, all NIS->LDAP mappings are set up from passwd.
+#nisLDAPattributeFromField netid.pass: \
+# ("unix.%s@*", uidNumber)=rf_key, \
+# (gidNumber)=("%s", (data), " "), \
+# description=rf_comment
+nisLDAPattributeFromField netid.pass: \
+ ("unix.%s@*", uidNumber)=rf_searchkey
+
+# netid.host
+#
+# Commented out because, unless remote domains (and thus /etc/netid) is
+# supported, all NIS->LDAP mappings are set up from hosts.
+#nisLDAPattributeFromField netid.host: \
+# dn=("cn=%s+ipHostNumber=%s,", data, \
+# ldap:ipHostNumber:?one?("cn=%s", data)), \
+# ipHostNumber=ldap:ipHostNumber:?one?("cn=%s", data), \
+# ("unix.%s@*", cn)=rf_key, \
+# description=rf_comment
+nisLDAPattributeFromField netid.host: \
+ ("unix.%s@*", cn)=rf_searchkey
+
+# netmasks.byaddr
+nisLDAPattributeFromField netmasks.byaddr: \
+ dn=("ipNetworkNumber=%s,", rf_ipkey ), \
+ ipNetworkNumber=rf_ipkey, \
+ ipNetmaskNumber=mask, \
+ description=rf_comment
+
+# networks.
+nisLDAPattributeFromField networks.byname: \
+ dn=("ipNetworkNumber=%s,", number ), \
+ cn=name, \
+ cn=rf_key
+nisLDAPattributeFromField networks.byaddr: \
+ dn=("ipNetworkNumber=%s,", rf_key ), \
+ cn=name
+nisLDAPattributeFromField networks: \
+ (cn)=(aliases, " "), \
+ ipNetworkNumber=number, \
+ description=rf_comment
+' >> $MAP_FILE
+
+
+# passwd syntax is different when passwd.adjunct map is present.
+# So, need to handle the various possibilities
+
+_MAP=passwd.adjunct.byname
+
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+
+ # Just put the passwd.adjunct syntax in comment form
+
+ echo '# passwd
+nisLDAPattributeFromField passwd.byname: \
+ dn=("uid=%s,", rf_key ), \
+ uid=rf_key, \
+ uidNumber=uid
+nisLDAPattributeFromField passwd.byuid: \
+ dn=("uid=%s,", name ), \
+ uidNumber=rf_key, \
+ uid=name
+nisLDAPattributeFromField passwd: \
+ cn=name, \
+ userPassword=("{crypt}%s",passwd), \
+ gidNumber=gid, \
+ gecos=gecos, \
+ homeDirectory=home, \
+ loginShell=shell
+
+#
+# If you are using passwd.adjunct, comment the passwd section above
+# and uncomment the following passwd and passwd.adjunct sections
+#
+# passwd
+#nisLDAPattributeFromField passwd.byname: \
+# dn=("uid=%s,", rf_key ), \
+# uid=rf_key, \
+# uidNumber=uid
+#nisLDAPattributeFromField passwd.byuid: \
+# dn=("uid=%s,", name ), \
+# uidNumber=rf_key, \
+# uid=name
+#nisLDAPattributeFromField passwd: \
+# cn=name, \
+# gidNumber=gid, \
+# gecos=gecos, \
+# homeDirectory=home, \
+# loginShell=shell
+
+# passwd.adjunct
+#nisLDAPattributeFromField passwd.adjunct.byname: \
+# dn=("uid=%s,", rf_key ), \
+# uid=name, \
+# userPassword=("{crypt}%s",passwd)
+' >> $MAP_FILE
+
+else
+
+ # Find the domains in which passwd.adjunct map exists.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # All the domains have passwd.adjunct map. So, put the right
+ # passwd syntax and comment-in the passwd.adjunct syntax.
+
+
+ echo '# passwd
+#nisLDAPattributeFromField passwd.byname: \
+# dn=("uid=%s,", rf_key ), \
+# uid=rf_key, \
+# uidNumber=uid
+#nisLDAPattributeFromField passwd.byuid: \
+# dn=("uid=%s,", name ), \
+# uidNumber=rf_key, \
+# uid=name
+#nisLDAPattributeFromField passwd: \
+# cn=name, \
+# userPassword=("{crypt}%s",passwd), \
+# gidNumber=gid, \
+# gecos=gecos, \
+# homeDirectory=home, \
+# loginShell=shell
+
+# If you are not using passwd.adjunct, uncomment the passwd section above
+# and comment the following passwd and passwd.adjunct sections
+#
+# passwd
+nisLDAPattributeFromField passwd.byname: \
+ dn=("uid=%s,", rf_key ), \
+ uid=rf_key, \
+ uidNumber=uid
+nisLDAPattributeFromField passwd.byuid: \
+ dn=("uid=%s,", name ), \
+ uidNumber=rf_key, \
+ uid=name
+nisLDAPattributeFromField passwd: \
+ cn=name, \
+ gidNumber=gid, \
+ gecos=gecos, \
+ homeDirectory=home, \
+ loginShell=shell
+
+# passwd.adjunct
+nisLDAPattributeFromField passwd.adjunct.byname: \
+ dn=("uid=%s,", rf_key ), \
+ uid=name, \
+ userPassword=("{crypt}%s",passwd)
+' >> $MAP_FILE
+
+ else
+ # Not every domain has passwd.adjunct map.
+
+ # First put the password syntax with domain name for domains
+ # in which passwd.adjunct exists.
+
+ echo "# passwd" >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPattributeFromField passwd.byname,${_DMN}: \\
+ dn=(\"uid=%s,\", rf_key ), \\
+ uid=rf_key, \\
+ uidNumber=uid
+nisLDAPattributeFromField passwd.byuid,${_DMN}: \\
+ dn=(\"uid=%s,\", name ), \\
+ uidNumber=rf_key, \\
+ uid=name
+nisLDAPattributeFromField passwd,${_DMN}: \\
+ cn=name, \\
+ gidNumber=gid, \\
+ gecos=gecos, \\
+ homeDirectory=home, \\
+ loginShell=shell
+" >> $MAP_FILE
+ done
+
+ # Now put the other passwd syntax. We do not need to
+ # append the domain name here.
+
+ echo '
+nisLDAPattributeFromField passwd.byname: \
+ dn=("uid=%s,", rf_key ), \
+ uid=rf_key, \
+ uidNumber=uid
+nisLDAPattributeFromField passwd.byuid: \
+ dn=("uid=%s,", name ), \
+ uidNumber=rf_key, \
+ uid=name
+nisLDAPattributeFromField passwd: \
+ cn=name, \
+ userPassword=("{crypt}%s",passwd), \
+ gidNumber=gid, \
+ gecos=gecos, \
+ homeDirectory=home, \
+ loginShell=shell
+' >> $MAP_FILE
+
+ # Now we need to put the passwd.adjunct syntax for domains
+ # in which this map exists.
+
+ echo "# passwd.adjunct" >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPattributeFromField passwd.adjunct.byname,${_DMN}: \\
+ dn=(\"uid=%s,\", rf_key ), \\
+ uid=name, \\
+ userPassword=(\"{crypt}%s\",passwd)
+" >> $MAP_FILE
+ done
+
+ fi
+
+fi
+
+echo '
+# This map is never created but yppasswd uses the mapping to extract password
+# aging information from the DIT.
+nisLDAPattributeFromField ageing.byname: \
+ dn=("uid=%s,", rf_key ), \
+ uid=name, \
+ shadowLastChange=lastchg, \
+ shadowMin=min, \
+ shadowMax=max, \
+ shadowWarning=warn, \
+ shadowInactive=inactive, \
+ shadowExpire=expire, \
+ shadowFlag=flag
+
+# printers.conf.byname
+nisLDAPattributeFromField printers.conf.byname: \
+ dn=("printer-uri=%s,", rf_key ), \
+ printer-name=rf_key, \
+ (printer-aliases)=(names, "|"), \
+ sun-printer-bsdaddr=(values, "*bsdaddr=%s:*"), \
+ (sun-printer-kvp)=(values,":"), \
+ description=rf_comment
+
+# prof_attr
+nisLDAPattributeFromField prof_attr: \
+ dn=("cn=%s,", rf_key ), \
+ cn=name, \
+ SolarisAttrReserved1=res1, \
+ SolarisAttrReserved2=res2, \
+ SolarisAttrLongDesc=desc, \
+ SolarisAttrKeyValue=attrs
+
+# project
+nisLDAPattributeFromField project.byname: \
+ dn=("SolarisProjectName=%s,", rf_key )
+nisLDAPattributeFromField project.byprojid: \
+ dn=("SolarisProjectName=%s,", name ), \
+ SolarisProjectID=rf_searchkey
+nisLDAPattributeFromField project: \
+ SolarisProjectName=name, \
+ SolarisProjectID=projID, \
+ (memberUid)=(users, ","), \
+ (memberGid)=(groups, ","), \
+ (SolarisProjectAttr)=(attrs, ";"), \
+ description=comment
+
+# protocols
+nisLDAPattributeFromField protocols.byname: \
+ ipProtocolNumber=number, \
+ cn=rf_searchkey
+nisLDAPattributeFromField protocols.bynumber: \
+ ipProtocolNumber=rf_key, \
+ description=rf_comment
+nisLDAPattributeFromField protocols: \
+ dn=("cn=%s,", name ), \
+ (cn)=(aliases, " "), \
+ cn=name
+
+# rpc.bynumber
+nisLDAPattributeFromField rpc.bynumber: \
+ dn=("cn=%s,", name ), \
+ oncRpcNumber=rf_key, \
+ (cn)=(aliases, " "), \
+ cn=name, \
+ description=rf_comment
+
+# services
+# services.byservicename rule is only used to speed single search
+nisLDAPattributeFromField services.byservicename: \
+ ("%s/%s", cn, ipServiceProtocol) = rf_searchkey
+
+nisLDAPattributeFromField services.byname: \
+ dn=("cn=%s+ipServiceProtocol=%s,", name, protocol ), \
+ ("*/%s", ipServiceProtocol)=rf_key, \
+ ("%s/*", ipServicePort)=rf_key, \
+ (cn)=(aliases, " "), \
+ cn=name, \
+ description=rf_comment
+
+# timezone.byname
+nisLDAPattributeFromField timezone.byname: \
+ dn=("cn=%s,", rf_key ), \
+ cn=hostName, \
+ nisplusTimeZone=zoneName, \
+ description=comment
+
+# user_attr
+nisLDAPattributeFromField user_attr: \
+ dn=("uid=%s,", rf_key ), \
+ uid=rf_key, \
+ SolarisUserAttr=qualifier, \
+ SolarisUserReserved1=res1, \
+ SolarisUserReserved2=res2, \
+ SolarisAttrKeyValue=attrs
+
+# publickey.byname
+nisLDAPattributeFromField keys.host: \
+ dn=("%s", ldap:dn:?one?("cn=%s", (yp:rf_key, "unix.%s@*"))), \
+ nisPublicKey=publicKey, \
+ nisSecretKey=secretKey
+
+nisLDAPattributeFromField keys.pass: \
+ dn=("%s", ldap:dn:?one?("uidNumber=%s", (yp:rf_key, "unix.%s@*"))), \
+ nisPublicKey=publicKey, \
+ nisSecretKey=secretKey
+
+nisLDAPattributeFromField keys.nobody: \
+ dn=("uid=%s,",yp:rf_key), \
+ cn=rf_key, \
+ nisPublicKey=publicKey, \
+ nisSecretKey=secretKey
+
+# ypservers. This derived from IPlanet implementation not RFC.
+nisLDAPattributeFromField ypservers: \
+ dn=("cn=%s,", rf_key), \
+ cn=rf_key
+' >> $MAP_FILE
+}
+
+#
+# List all the non-default auto.* and custom maps.
+#
+list_auto_and_custom_nisLDAPattributeFromField()
+{
+
+# auto.* entries are easy.
+if [ ${#ALL_DMN_AUTO_CUST_MAPS[*]} -gt 0 ]; then
+ echo "# Non-default custom auto maps (auto.*)\n" >> $MAP_FILE
+fi
+
+for _MAP in ${ALL_DMN_AUTO_CUST_MAPS[*]}
+do
+ echo "\
+# ${_MAP}
+nisLDAPattributeFromField ${_MAP}: \\
+ dn=(\"automountKey=%s,\", rf_key ), \\
+ automountKey=rf_key, \\
+ automountInformation=value
+" >> $MAP_FILE
+done
+
+# Since we do not have enough information to generate
+# entries for other custom maps, best we can do is to
+# log this map names and ask user to take care of them.
+
+ask_user_to_update_the_custom_map_entries_too
+
+}
+
+
+#
+# List mapping of named fields to DIT entries
+#
+create_nisLDAPattributeFromField()
+{
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo '
+# nisLDAPattributeFromField : It specifies how an LDAP attribute
+# value is derived from a NIS entries field values.
+#
+# The format of nisLDAPattributeFromField entry is :
+# mapName ":" fieldattrspec *("," fieldattrspec )
+' >> $MAP_FILE
+
+# List all the default entries anyway.
+list_default_nisLDAPattributeFromField
+
+# List all the non-default auto.* and custom maps.
+list_auto_and_custom_nisLDAPattributeFromField
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+}
+
+
+#
+# List all the default nisLDAPattributeFromField entries
+#
+list_default_nisLDAPfieldFromAttribute()
+{
+echo '
+# Describe how named fields are mapped from DIT entries.
+
+# audit_user
+nisLDAPfieldFromAttribute audit_user: \
+ ("uid=%s,*", rf_key)=dn, \
+ ("uid=%s,*", name)=dn, \
+ alwaysAuditFlags=SolarisAuditAlways, \
+ neverAuditFlags=SolarisAuditNever
+
+# auto.home
+nisLDAPfieldFromAttribute auto.home: \
+ rf_key=automountKey, \
+ value=automountInformation
+
+# auto.master
+nisLDAPfieldFromAttribute auto.master: \
+ rf_key=automountKey, \
+ value=automountInformation
+
+# auth_attr
+nisLDAPfieldFromAttribute auth_attr: \
+ rf_key=cn, \
+ name=cn, \
+ res1=SolarisAttrReserved1, \
+ res2=SolarisAttrReserved2, \
+ short_desc=SolarisAttrShortDesc, \
+ long_desc=SolarisAttrLongDesc, \
+ attrs=SolarisAttrKeyValue
+
+# Exec_attr. Because of messy NIS keys special handlind is required here
+nisLDAPfieldFromAttribute exec_attr: \
+ rf_key=("%s:%s:%s",cn,SolarisKernelSecurityPolicy, \
+ solarisProfileId), \
+ name=cn, \
+ policy=SolarisKernelSecurityPolicy, \
+ type=SolarisProfileType, \
+ res1=SolarisAttrReserved1, \
+ res2=SolarisAttrReserved2, \
+ id=SolarisProfileId, \
+ attrs=SolarisAttrKeyValue
+
+
+# ethers
+nisLDAPfieldFromAttribute ethers.byname: \
+ rf_key=cn
+nisLDAPfieldFromAttribute ethers.byaddr: \
+ rf_key=macAddress
+nisLDAPfieldFromAttribute ethers: \
+ name=cn, \
+ addr=macAddress, \
+ rf_comment=description
+
+# bootparams. Must be done after ethers
+nisLDAPfieldFromAttribute bootparams: \
+ rf_key=cn, \
+ params=("%s ", (bootParameter), " ")
+' >> $MAP_FILE
+
+# group syntax is different when group.adjunct map is present.
+# So, need to handle the various possibilities
+
+_MAP=group.adjunct.byname
+
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+
+ # Just put the group.adjunct syntax in comment form
+
+ echo '# group
+nisLDAPfieldFromAttribute group.byname: \
+ rf_key=cn
+nisLDAPfieldFromAttribute group.bygid: \
+ rf_key=gidNumber
+nisLDAPfieldFromAttribute group: \
+ gid=gidNumber, \
+ name=cn, \
+ ("{crypt}%s", passwd)=userPassword, \
+ users=("%s,", (memberUid), ",")
+
+#
+# If you are using group.adjunct, comment the group section above
+# and uncomment the following group and group.adjunct section
+#
+# group
+#nisLDAPfieldFromAttribute group.byname: \
+# rf_key=cn
+#nisLDAPfieldFromAttribute group.bygid: \
+# rf_key=gidNumber
+#nisLDAPfieldFromAttribute group: \
+# gid=gidNumber, \
+# name=cn, \
+# passwd=("#$%s", cn), \
+# users=("%s,", (memberUid), ",")
+
+# group.adjunct
+#nisLDAPfieldFromAttribute group.adjunct.byname: \
+# rf_key=cn, \
+# name=cn, \
+# ("{crypt}%s", passwd)=userPassword
+' >> $MAP_FILE
+
+else
+
+ # Find the domains in which group.adjunct map exists.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # All the domains have group.adjunct map.
+
+
+ echo '# group
+#nisLDAPfieldFromAttribute group.byname: \
+# rf_key=cn
+#nisLDAPfieldFromAttribute group.bygid: \
+# rf_key=gidNumber
+#nisLDAPfieldFromAttribute group: \
+# gid=gidNumber, \
+# name=cn, \
+# ("{crypt}%s", passwd)=userPassword, \
+# users=("%s,", (memberUid), ",")
+
+#
+# If you are not using group.adjunct, comment the group section above
+# and uncomment the following group and group.adjunct sections
+#
+# group
+nisLDAPfieldFromAttribute group.byname: \
+ rf_key=cn
+nisLDAPfieldFromAttribute group.bygid: \
+ rf_key=gidNumber
+nisLDAPfieldFromAttribute group: \
+ gid=gidNumber, \
+ name=cn, \
+ passwd=("#$%s", cn), \
+ users=("%s,", (memberUid), ",")
+
+#
+# group.adjunct
+nisLDAPfieldFromAttribute group.adjunct.byname: \
+ rf_key=cn, \
+ name=cn, \
+ ("{crypt}%s", passwd)=userPassword
+' >> $MAP_FILE
+
+ else
+ # Not every domain has group.adjunct map.
+
+ echo "# group" >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPfieldFromAttribute group.byname,${_DMN}: \\
+ rf_key=cn
+nisLDAPfieldFromAttribute group.bygid,${_DMN}: \\
+ rf_key=gidNumber
+nisLDAPfieldFromAttribute group,${_DMN}: \\
+ gid=gidNumber, \\
+ name=cn, \\
+ passwd=(\"#$%s\", cn), \\
+ users=(\"%s,\", (memberUid), \",\")
+" >> $MAP_FILE
+ done
+
+ # Now put the generic group syntax. We do not need to
+ # append the domain name here.
+
+ echo '
+nisLDAPfieldFromAttribute group.byname: \
+ rf_key=cn
+nisLDAPfieldFromAttribute group.bygid: \
+ rf_key=gidNumber
+nisLDAPfieldFromAttribute group: \
+ gid=gidNumber, \
+ name=cn, \
+ ("{crypt}%s", passwd)=userPassword, \
+ users=("%s,", (memberUid), ",")
+' >> $MAP_FILE
+
+ # Now we need to put the group.adjunct syntax for domains
+ # in which this map exists.
+
+ echo "#
+# group.adjunct
+# " >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPfieldFromAttribute group.adjunct.byname,${_DMN}: \\
+ rf_key=cn, \\
+ name=cn, \\
+ (\"{crypt}%s\", passwd)=userPassword
+" >> $MAP_FILE
+
+ done
+
+ fi
+
+fi
+
+echo '
+# hosts
+nisLDAPfieldFromAttribute hosts.byaddr: \
+ rf_ipkey=ipHostNumber
+nisLDAPfieldFromAttribute hosts.byname: \
+ (rf_key)=(cn)
+nisLDAPfieldFromAttribute hosts: \
+ ("cn=%s+ipHostNumber=*", canonicalName)=dn, \
+ addr=ipHostNumber, \
+ aliases=("%s ", (cn) - yp:canonicalName, " "), \
+ rf_comment=description
+
+nisLDAPfieldFromAttribute multihosts: \
+ ("cn=%s+ipHostNumber=*", canonicalName)=dn, \
+ (rf_key)=("YP_MULTI_%s", cn), \
+ aliases=("%s ", (cn) - yp:canonicalName, " "), \
+ rf_comment=description, \
+ (tmp)=("%s", ipHostNumber:?one?("(&(cn=%s) \
+ (ipHostNumber=*.*))", yp:canonicalName)), \
+ addr=("%s,", (yp:tmp), ",")
+
+# ipnodes
+nisLDAPfieldFromAttribute ipnodes.byaddr: \
+ rf_ipkey=ipHostNumber
+nisLDAPfieldFromAttribute ipnodes.byname: \
+ ("cn=%s+ipHostNumber=*", rf_key)=dn
+nisLDAPfieldFromAttribute ipnodes: \
+ ("cn=%s+ipHostNumber=*", canonicalName)=dn, \
+ addr=ipHostNumber, \
+ aliases=("%s ", (cn) - yp:canonicalName, " "), \
+ rf_comment=description
+
+nisLDAPfieldFromAttribute multiipnodes: \
+ ("cn=%s+ipHostNumber=*", canonicalName)=dn, \
+ (rf_key)=("YP_MULTI_%s", cn), \
+ aliases=("%s ", (cn) - yp:canonicalName, " "), \
+ rf_comment=description, \
+ (tmp)=("%s", ipHostNumber:?one?("(&(cn=%s) \
+ (ipHostNumber=*:*))", yp:canonicalName)), \
+ addr=("%s,", (yp:tmp), ",")
+
+#mail.aliases
+nisLDAPfieldFromAttribute mail.aliases: \
+ rf_key=mail, \
+ addresses= ("%s,", (mgrprfc822mailmember), ","), \
+ rf_comment=description
+
+#mail.mapping
+nisLDAPfieldFromAttribute mail.mapping: \
+ rf_key=mgrprfc822mailmember, \
+ address=mail, \
+ rf_comment=description
+
+# netgroup.
+nisLDAPfieldFromAttribute netgroup: \
+ rf_key=cn, \
+ (group)=(memberNisNetgroup), \
+ ("(%s,%s,%s)", host, user, domain)= \
+ (nisNetgroupTriple), \
+ rf_comment=description
+
+# netid.pass
+nisLDAPfieldFromAttribute netid.pass: \
+ number=uidNumber, \
+ (tmp)=("%s", gidNumber:ou=group,?one?\
+ ("memberUid=%s", ldap:uid)), \
+ sgid=("%s,", (yp:tmp) - gidNumber, ","), \
+ data=("%s,%s", gidNumber, yp:sgid), \
+ data=gidNumber, \
+ (rf_key)=("unix.%s@%s", yp:number, yp:rf_domain)
+
+# netid.host
+nisLDAPfieldFromAttribute netid.host: \
+ ("cn=%s+ipHostNumber=*", data)=dn, \
+ number=("0"), \
+ (rf_key)=("unix.%s@%s", yp:data, yp:rf_domain)
+
+# netmasks.byaddr
+nisLDAPfieldFromAttribute netmasks.byaddr: \
+ ("ipNetworkNumber=%s,*", rf_ipkey)=dn, \
+ mask=ipNetmaskNumber, \
+ rf_comment=description
+
+# networks.
+nisLDAPfieldFromAttribute networks.byname: \
+ (rf_key)=(cn)
+nisLDAPfieldFromAttribute networks.byaddr: \
+ ("ipNetworkNumber=%s,*", rf_key)=dn
+nisLDAPfieldFromAttribute networks: \
+ name=cn, \
+ aliases=("%s ", (cn) - yp:name, " "), \
+ number=ipNetworkNumber, \
+ rf_comment=description
+' >> $MAP_FILE
+
+# passwd syntax is different when passwd.adjunct map is present.
+# So, need to handle the various possibilities
+
+_MAP=passwd.adjunct.byname
+
+if ! present $_MAP $ALL_DMN_DEF_MAPLIST
+then
+
+ # Just put the passwd.adjunct syntax in comment form
+
+ echo '# passwd
+nisLDAPfieldFromAttribute passwd.byname: \
+ rf_key=uid
+nisLDAPfieldFromAttribute passwd.byuid: \
+ rf_key=uidNumber
+nisLDAPfieldFromAttribute passwd: \
+ name=uid, \
+ uid=uidNumber, \
+ ("{crypt}%s", passwd)=userPassword, \
+ gid=gidNumber, \
+ gecos=gecos, \
+ home=homeDirectory, \
+ shell=loginShell
+
+#
+# If you are using passwd.adjunct, comment the passwd section above
+# and uncomment the following passwd and passwd.adjunct sections
+#
+# passwd
+#nisLDAPfieldFromAttribute passwd.byname: \
+# rf_key=uid
+#nisLDAPfieldFromAttribute passwd.byuid: \
+# rf_key=uidNumber
+#nisLDAPfieldFromAttribute passwd: \
+# name=uid, \
+# uid=uidNumber, \
+# passwd=("##%s", uid), \
+# gid=gidNumber, \
+# gecos=gecos, \
+# home=homeDirectory, \
+# shell=loginShell
+
+# passwd.adjunct
+#nisLDAPfieldFromAttribute passwd.adjunct.byname: \
+# rf_key=uid, \
+# name=uid, \
+# ("{crypt}%s", passwd)=userPassword
+' >> $MAP_FILE
+
+else
+
+ # Find the domains in which passwd.adjunct map exists.
+ find_domains $_MAP DEF_MAPS
+
+ if [ $PRESENT_COUNT -eq $N2L_DMN_CNT ]
+ then
+
+ # All the domains have passwd.adjunct map. So, put the right
+ # passwd syntax and comment-in the passwd.adjunct syntax.
+
+
+ echo '# passwd
+#nisLDAPfieldFromAttribute passwd.byname: \
+# rf_key=uid
+#nisLDAPfieldFromAttribute passwd.byuid: \
+# rf_key=uidNumber
+#nisLDAPfieldFromAttribute passwd: \
+# name=uid, \
+# uid=uidNumber, \
+# ("{crypt}%s", passwd)=userPassword, \
+# gid=gidNumber, \
+# gecos=gecos, \
+# home=homeDirectory, \
+# shell=loginShell
+
+#
+# If you are not using passwd.adjunct, uncomment the passwd section
+# above and comment the following passwd and passwd.adjunct sections
+#
+# passwd
+nisLDAPfieldFromAttribute passwd.byname: \
+ rf_key=uid
+nisLDAPfieldFromAttribute passwd.byuid: \
+ rf_key=uidNumber
+nisLDAPfieldFromAttribute passwd: \
+ name=uid, \
+ uid=uidNumber, \
+ passwd=("##%s", uid), \
+ gid=gidNumber, \
+ gecos=gecos, \
+ home=homeDirectory, \
+ shell=loginShell
+
+#
+# passwd.adjunct Must follow passwd
+#
+nisLDAPfieldFromAttribute passwd.adjunct.byname: \
+ rf_key=uid, \
+ name=uid, \
+ ("{crypt}%s", passwd)=userPassword
+' >> $MAP_FILE
+
+ else
+ # Not every domain has passwd.adjunct map.
+
+ # First put the password syntax with domain name for domains
+ # in which passwd.adjunct exists.
+
+ echo "# passwd" >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPfieldFromAttribute passwd.byname,${_DMN}: \\
+ rf_key=uid
+nisLDAPfieldFromAttribute passwd.byuid,${_DMN}: \\
+ rf_key=uidNumber
+nisLDAPfieldFromAttribute passwd,${_DMN}: \\
+ name=uid, \\
+ uid=uidNumber, \\
+ passwd=(\"##%s\", uid), \\
+ gid=gidNumber, \\
+ gecos=gecos, \\
+ home=homeDirectory, \\
+ shell=loginShell
+" >> $MAP_FILE
+ done
+
+ # Now put the other passwd syntax. We do not need to
+ # append the domain name here.
+
+ echo '
+nisLDAPfieldFromAttribute passwd.byname: \
+ rf_key=uid
+nisLDAPfieldFromAttribute passwd.byuid: \
+ rf_key=uidNumber
+nisLDAPfieldFromAttribute passwd: \
+ name=uid, \
+ uid=uidNumber, \
+ ("{crypt}%s", passwd)=userPassword, \
+ gid=gidNumber, \
+ gecos=gecos, \
+ home=homeDirectory, \
+ shell=loginShell
+' >> $MAP_FILE
+
+ # Now we need to put the passwd.adjunct syntax for domains
+ # in which this map exists.
+
+ echo "#
+# passwd.adjunct Must follow passwd
+# " >> $MAP_FILE
+
+ for _DMN in $PRESENT_IN_DOMAINS
+ do
+
+ echo "\
+nisLDAPfieldFromAttribute passwd.adjunct.byname,${_DMN}: \\
+ rf_key=uid, \\
+ name=uid, \\
+ (\"{crypt}%s\", passwd)=userPassword
+" >> $MAP_FILE
+
+ done
+
+ fi
+
+fi
+
+echo '
+# This map is never created but yppasswd uses the mapping to extract password
+# ageing information from the DIT.
+nisLDAPfieldFromAttribute ageing.byname: \
+ rf_key=uid, \
+ name=uid, \
+ lastchg=shadowLastChange, \
+ min=shadowMin, \
+ max=shadowMax, \
+ warn=shadowWarning, \
+ inactive=shadowInactive, \
+ expire=shadowExpire, \
+ flag=shadowFlag
+
+# printers.conf.byname
+nisLDAPfieldFromAttribute printers.conf.byname: \
+ rf_key=printer-uri, \
+ names=("%s|", (printer-aliases), "|"), \
+ bsdaddr=("bsdaddr=%s", sun-printer-bsdaddr), \
+ kvps=("%s:", (sun-printer-kvp) - yp:bsdaddr), \
+ values=("%s:%s", yp:bsdaddr, yp:kvps), \
+ values=("%s:", yp:bsdaddr), \
+ values=yp:kvps, \
+ rf_comment=description
+
+# prof_attr
+nisLDAPfieldFromAttribute prof_attr: \
+ rf_key=cn, \
+ name=cn, \
+ res1=SolarisAttrReserved1, \
+ res2=SolarisAttrReserved2, \
+ desc=SolarisAttrLongDesc, \
+ attrs=SolarisAttrKeyValue
+
+# project
+nisLDAPfieldFromAttribute project.byname: \
+ rf_key=SolarisProjectName
+nisLDAPfieldFromAttribute project.byprojid: \
+ rf_key=SolarisProjectID
+nisLDAPfieldFromAttribute project: \
+ name=SolarisProjectName, \
+ projID=SolarisProjectID, \
+ comment=description, \
+ users=("%s,", (memberUid), ","), \
+ groups=("%s,", (memberGid), ","), \
+ attrs=("%s;", (SolarisProjectAttr), ";")
+
+# protocols
+nisLDAPfieldFromAttribute protocols.byname: \
+ ("cn=%s,*", rf_key)=dn, \
+ (rf_key)=(cn)
+nisLDAPfieldFromAttribute protocols.bynumber: \
+ rf_key=ipProtocolNumber, \
+ rf_comment=description
+nisLDAPfieldFromAttribute protocols: \
+ ("cn=%s,*", name)=dn, \
+ number=ipProtocolNumber, \
+ aliases=("%s ", (cn) - yp:name, " ")
+
+# rpc.bynumber
+nisLDAPfieldFromAttribute rpc.bynumber: \
+ rf_key=oncRpcNumber, \
+ number=oncRpcNumber, \
+ ("cn=%s,*", name)=dn, \
+ aliases=("%s ", (cn) - yp:name, " "), \
+ rf_comment=description
+
+# services
+nisLDAPfieldFromAttribute services.byname: \
+ rf_key = ("%s/%s", ipServicePort, ipServiceProtocol)
+nisLDAPfieldFromAttribute services.byservicename: \
+ (rf_key)=("%s/%s", cn, ipServiceProtocol), \
+ (rf_key)=(cn)
+nisLDAPfieldFromAttribute services: \
+ ("cn=%s+ipServiceProtocol=*", name)=dn, \
+ protocol=ipServiceProtocol, \
+ port=ipServicePort, \
+ aliases=("%s ", (cn) - yp:name, " "), \
+ rf_comment=description
+
+# timezone.byname
+nisLDAPfieldFromAttribute timezone.byname: \
+ rf_key=cn, \
+ hostName=cn, \
+ zoneName=nisplusTimeZone, \
+ rf_comment=description
+
+# user_attr
+nisLDAPfieldFromAttribute user_attr: \
+ ("uid=%s,*", rf_key)=dn, \
+ ("uid=%s,*", user)=dn, \
+ qualifier=SolarisUserAttr, \
+ res1=SolarisUserReserved1, \
+ res2=SolarisUserReserved2, \
+ attrs=SolarisAttrKeyValue
+
+# publickey.byname
+nisLDAPfieldFromAttribute keys.host: \
+ ("cn=%s+ipHostNumber=*", cname)=dn, \
+ rf_key=("unix.%s@%s", yp:cname, yp:rf_domain), \
+ publicKey=nisPublicKey, \
+ secretKey=nisSecretKey
+
+nisLDAPfieldFromAttribute keys.pass: \
+ rf_key=("unix.%s@%s", uidNumber, yp:rf_domain), \
+ publicKey=nisPublicKey, \
+ secretKey=nisSecretKey
+
+nisLDAPfieldFromAttribute keys.nobody: \
+ rf_key=uid, \
+ publicKey=nisPublicKey, \
+ secretKey=nisSecretKey
+
+# ypservers. This derived from IPlanet implementation not RFC.
+nisLDAPfieldFromAttribute ypservers: \
+ rf_key=cn
+' >> $MAP_FILE
+}
+
+
+#
+# List all the non-default auto.* and custom maps.
+#
+list_auto_and_custom_nisLDAPfieldFromAttribute()
+{
+
+# auto.* entries are easy.
+if [ ${#ALL_DMN_AUTO_CUST_MAPS[*]} -gt 0 ]; then
+ echo "# Non-default custom auto maps (auto.*)\n" >> $MAP_FILE
+fi
+
+for _MAP in ${ALL_DMN_AUTO_CUST_MAPS[*]}
+do
+ echo "\
+# ${_MAP}
+nisLDAPfieldFromAttribute ${_MAP}: \\
+ rf_key=automountKey, \\
+ value=automountInformation
+" >> $MAP_FILE
+done
+
+# Since we do not have enough information to generate
+# entries for other custom maps, best we can do is to
+# log this map names and ask user to take care of them.
+
+ask_user_to_update_the_custom_map_entries_too
+
+}
+
+
+#
+# List mapping of named fields from DIT entries
+#
+create_nisLDAPfieldFromAttribute()
+{
+
+[ CUST_CMT_NEEDED -eq 1 ] && echo '
+# nisLDAPfieldFromAttribute : It specifies how a NIS entries
+# field values are derived from LDAP attribute values.
+#
+# The format of nisLDAPfieldFromAttribute is :
+# mapName ":" fieldattrspec *("," fieldattrspec)
+' >> $MAP_FILE
+
+# List all the default entries anyway.
+list_default_nisLDAPfieldFromAttribute
+
+# List all the non-default auto.* and custom maps.
+list_auto_and_custom_nisLDAPfieldFromAttribute
+
+echo "
+#
+#------------------------------------------------------------------------------
+#
+" >> $MAP_FILE
+}
+
+
+
+# Main function for creating the mapping file
+create_mapping_file()
+{
+# Ask user the list of domains to be served by N2L
+create_n2l_domain_list
+
+# If there are no N2L domains or none selected, then exit
+if [ $N2L_DMN_CNT -eq 0 ]; then
+ echo "There are no domains to serve. No mapping file generated."
+ return 1
+fi
+
+while :
+do
+ get_ans "Enter the mapping file name (h=help):" "${MAP_FILE}"
+
+ # If help continue, otherwise break.
+ case "$ANS" in
+ [Hh] | help | Help | \?) display_msg new_mapping_file_name_help ;;
+ * ) break ;;
+ esac
+done
+
+MAP_FILE=${ANS}
+[ $DEBUG -eq 1 ] && MAP_FILE = $MAP_FILE
+
+# Backup existing mapping file if selected
+check_back_mapping_file
+
+# To prevent from leaving a partial mapping file in case some error
+# or signal takes place which might result in machine starting in N2L
+# mode at next reboot, store the output being generated in a temporary
+# file first, and move it at the final destination only at the end if
+# everything goes fine.
+
+_MAP_FILE=$MAP_FILE
+MAP_FILE=${TMPDIR}/${TMPMAP}.$$
+
+echo "Generating mapping file temporarily as \"${MAP_FILE}\""
+
+# Place copyright information
+put_mapping_file_copyright_info
+
+
+# Prepare various map lists for each domain
+create_map_lists
+
+# List domains and contexts
+get_nisLDAPdomainContext
+
+# List domains for which passwords should be changed
+get_nisLDAPyppasswddDomains
+
+# List databaseId mappings (aliases)
+create_nisLDAPdatabaseIdMapping
+
+# List comment character for maps
+create_nisLDAPcommentChar
+
+# List SECURE and INTERDOMAIN flags
+create_nisLDAPmapFlags
+
+# List TTL values
+ create_nisLDAPentryTtl
+
+# List name fields
+create_nisLDAPnameFields
+
+# List split fields and repeated fields seperators.
+create_split_field_and_repeatedfield_seperators
+
+# List association of maps with RDNs and object classes.
+create_nisLDAPobjectDN
+
+# List mapping of named fields to DIT entries
+create_nisLDAPattributeFromField
+
+# List mapping of named fields from DIT entries
+create_nisLDAPfieldFromAttribute
+
+
+# We are done, so move back the mapping file from temp. location
+# to actual location.
+# In case the mapping file name has a directory component which does
+# not exist, then create it now, otherwise 'mv' will return error.
+
+DIR_TO_CREATE=`dirname ${_MAP_FILE}`
+mkdir -p ${DIR_TO_CREATE}
+
+echo "Moving output from temporary file ($MAP_FILE) to actual file ($_MAP_FILE)"
+mv $MAP_FILE $_MAP_FILE
+
+# Revert back the mapping file name in case needed.
+MAP_FILE=$_MAP_FILE
+echo "Finished creation of mapping file ( $MAP_FILE )"
+
+}
+
+
+#
+# Main function for creating config file (ypserv)
+#
+process_config_file()
+{
+# Ask for confirmation if the file name is not specified.
+
+if [ $CONFIG_FILE_SPECIFIED -eq 0 ]; then
+ display_msg no_config_file_name_specified
+
+ get_confirm_nodef "Do you want to create the config file (y/n) ?"
+
+ [ $? -eq 0 ] && return 0
+
+ while :
+ do
+ get_ans "Enter the config file name (h=help):" "${CONFIG_FILE}"
+
+ # If help continue, otherwise break.
+ case "$ANS" in
+ [Hh] | help | Help | \?) display_msg new_config_file_name_help ;;
+ * ) break ;;
+ esac
+ done
+
+ CONFIG_FILE=${ANS}
+ [ $DEBUG -eq 1 ] && CONFIG_FILE = $CONFIG_FILE
+
+fi
+
+# Backup existing config file if selected
+check_back_config_file
+
+# Create config file
+create_config_file
+}
+
+
+#
+# Main function for creating mapping file (NISLDAPmapping)
+#
+process_mapping_file()
+{
+# Ask for confirmation if the file name is not specified.
+
+if [ $MAPPING_FILE_SPECIFIED -eq 0 ]; then
+ display_msg no_mapping_file_name_specified
+
+ get_confirm_nodef "Do you want to create the mapping file (y/n) ?"
+
+ [ $? -eq 0 ] && return 0
+
+
+fi
+
+# Create mapping file
+create_mapping_file
+}
+
+###########################################
+########### MAIN ###########
+###########################################
+
+PROG=`basename $0` # Program name
+ABS_PROG=$0 # absolute path needed
+
+# Only superuser should be able to run this script.
+is_root_user
+if [ $? -ne 0 ]; then
+ echo "ERROR : Only root can run $PROG"
+ exit 1
+fi
+
+# Initialize things
+init
+
+# Parse command line arguments.
+parse_arg $*
+
+# Create config file (ypserv)
+process_config_file
+
+# Create mapping file (NISLDAPmapping).
+process_mapping_file
+
+# Cleanup temp files and directories unless debug.
+[ $DEBUG -eq 0 ] && cleanup
+
+exit 0
diff --git a/usr/src/cmd/ypcmd/yp2lscripts/ypmap2src.sh b/usr/src/cmd/ypcmd/yp2lscripts/ypmap2src.sh
new file mode 100644
index 0000000000..b52fe8e8bc
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp2lscripts/ypmap2src.sh
@@ -0,0 +1,971 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ypmap2src -- script to generate source files from YP maps.
+#
+
+
+# Please save a copy of this script before making any changes.
+
+
+usage()
+{
+echo "Usage: $PROG [-t] [[-c custom-map-name] ...] [-d domain] -o output-directory [[source-file] ...]"
+echo " t - Generate source files from TRADITIONAL NIS MAPS, default is NIS2LDAP maps."
+echo " c - Name of the custom map for which source file needs to be generated."
+echo " d - Specify a different domain, default is local system domain name."
+echo " o - Specify the output directory where source files can be generated."
+echo "source-file - The name of the source file for which needs to be generated."
+exit 0
+}
+
+parse_argument()
+{
+while getopts "tc:d:o:" ARG
+do
+ case $ARG in
+
+ t) N2LPREFIX=""
+ MAP_LIST="$NIS_ONLY_MAP_LIST"
+ ;;
+ c) CUST_LIST="$CUST_LIST $OPTARG"
+ ;;
+ d) DOMAIN=$OPTARG
+ MAPDIR=/var/yp/"$DOMAIN"
+ ;;
+ o) OUTDIR=$OPTARG
+ ;;
+ *) echo "ERROR : Invalid argument"
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+# This is to handle if "-t" is supplied after "-c"
+for MAP in $CUST_LIST
+do
+ CUST_MAP_LIST="$CUST_MAP_LIST ${N2LPREFIX}$MAP"
+done
+
+if [ -z "$OUTDIR" ]; then
+ echo "ERROR : output directory has to be specified."
+ usage
+ exit 1
+fi
+
+# Set source list if supplied
+shift `expr $OPTIND - 1`
+CMDLINE_SRC_LIST="$@"
+
+[ $DEBUG -eq 1 ] && echo CMDLINE_SRC_LIST = $CMDLINE_SRC_LIST
+
+# If source(s) supplied on command line, then generate ONLY those file(s).
+
+if [ "$CMDLINE_SRC_LIST" != "" ]; then
+ MAP_LIST=""
+ CMDLINE_SRCS=1
+
+ for SRC in $CMDLINE_SRC_LIST
+ do
+ [ $DEBUG -eq 1 ] && echo Parsing Command line SRC = $SRC
+
+ case $SRC in
+ passwd )
+ MAP=${N2LPREFIX}passwd.byuid
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ group )
+ MAP=${N2LPREFIX}group.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ hosts )
+ MAP=${N2LPREFIX}hosts.byaddr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ ipnodes )
+ MAP=${N2LPREFIX}ipnodes.byaddr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ ethers )
+ MAP=${N2LPREFIX}ethers.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ networks )
+ MAP=${N2LPREFIX}networks.byaddr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ rpc )
+ MAP=${N2LPREFIX}rpc.bynumber
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ services )
+ MAP=${N2LPREFIX}services.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ protocols )
+ MAP=${N2LPREFIX}protocols.bynumber
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ netgroup )
+ MAP=${N2LPREFIX}netgroup
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ bootparams )
+ MAP=${N2LPREFIX}bootparams
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ aliases )
+ MAP=${N2LPREFIX}mail.aliases
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ publickey )
+ MAP=${N2LPREFIX}publickey.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ netid )
+ MAP=${N2LPREFIX}netid.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ netmasks )
+ MAP=${N2LPREFIX}netmasks.byaddr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ passwd.adjunct )
+ MAP=${N2LPREFIX}passwd.adjunct.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ group.adjunct )
+ MAP=${N2LPREFIX}group.adjunct.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ timezone )
+ MAP=${N2LPREFIX}timezone.byname
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ auto.* )
+ MAP=${N2LPREFIX}${SRC}
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ auth_attr )
+ MAP=${N2LPREFIX}auth_attr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ exec_attr )
+ MAP=${N2LPREFIX}exec_attr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ prof_attr )
+ MAP=${N2LPREFIX}prof_attr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ user_attr )
+ MAP=${N2LPREFIX}user_attr
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ audit_user )
+ MAP=${N2LPREFIX}audit_user
+ MAP_LIST="$MAP_LIST $MAP"
+ ;;
+ *) # Not a default source, could be a custom source.
+ # Then generate source files from all the available
+ # DBM files for this custom source.
+
+ MAPFOUND=0
+
+ for dbmfile in $MAPDIR/${N2LPREFIX}${SRC}.dir \
+ $MAPDIR/${N2LPREFIX}${SRC}.*.dir
+ do
+ MAP=`basename $dbmfile .dir`
+ if [ -f $MAPDIR/${MAP}.pag ]; then
+ MAPFOUND=1
+ CUST_MAP_LIST="$CUST_MAP_LIST $MAP"
+ fi
+ done
+
+ [ $MAPFOUND -eq 0 ] && \
+ echo ERROR : No maps found for $SRC. Skipping..
+ ;;
+ esac
+ done
+
+fi
+
+}
+
+
+is_root_user()
+{
+ case `id` in
+ uid=0\(root\)*) return 0
+ ;;
+ * ) return 1
+ ;;
+ esac
+}
+
+
+create_passwd()
+{
+SRCFILE=passwd
+SHADOW=shadow
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort the entries in ascending order of uid
+sort -n -t: -k3,3 $TMPDIR/${MAP}.cut > $TMPDIR/${MAP}.sort
+
+# If passwd.adjunct is used, the actual password is stored in
+# this map, and the passwd map contains "##<uid>" as the passwd.
+# In that case, do not generate the shadow file.
+
+UID=`head -1 $TMPDIR/${MAP}.sort | cut -f1 -d:`
+PSWD=`head -1 $TMPDIR/${MAP}.sort | cut -f2 -d:`
+if [ "$PSWD" != "##${UID}" ]; then
+
+ #Create the shadow file with blank passwd aging information
+ cut -f 1,2 -d: $TMPDIR/${MAP}.sort |
+ sed 's/$/:::::::/' > $OUTDIR/$SHADOW
+
+ #Make the shadow file readable to root only
+ chmod 400 $OUTDIR/$SHADOW
+
+ #Create the passwd file with "x" as the passwd
+ awk ' BEGIN { FS = ":"; OFS = ":"}
+ {$2 = "x"; print}' $TMPDIR/${MAP}.sort > $OUTDIR/$SRCFILE
+else
+ cp $TMPDIR/${MAP}.sort $OUTDIR/$SRCFILE
+fi
+
+}
+
+
+create_group()
+{
+SRCFILE=group
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort the entries in ascending order of gid
+sort -n -t: -k3,3 $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_hosts()
+{
+SRCFILE=hosts
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort the hosts ip addresses in ascending order
+sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4 $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_ipnodes()
+{
+SRCFILE=ipnodes
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+grep -v "::" $TMPDIR/${MAP}.cut >$TMPDIR/${MAP}.V4
+grep "::" $TMPDIR/${MAP}.cut >$TMPDIR/${MAP}.V6
+
+# Sort the ip addresses in ascending order
+sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4 $TMPDIR/${MAP}.V4 > $OUTDIR/$SRCFILE
+
+# V6 addresses due to hex chars, can't be sorted this way.
+# So just do the default string sort.
+sort $TMPDIR/${MAP}.V6 >> $OUTDIR/$SRCFILE
+}
+
+
+create_ethers()
+{
+SRCFILE=ethers
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort ethernet addresses based on host names
+sort -b -k2 $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_networks()
+{
+SRCFILE=networks
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort networks based on their names
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_rpc()
+{
+SRCFILE=rpc
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort entries in the increasing order of RPC number
+sort -n -k2 $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_services()
+{
+SRCFILE=services
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort entries in the increasing order of RPC number
+sort -n -k2 $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_protocols()
+{
+SRCFILE=protocols
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort entries in the increasing order of RPC number
+sort -n -k2 $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_netgroup()
+{
+SRCFILE=netgroup
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+cp $TMPDIR/${MAP}.grep $OUTDIR/$SRCFILE
+}
+
+
+create_bootparams()
+{
+SRCFILE=bootparams
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Sort the entries
+sort $TMPDIR/${MAP}.grep > $OUTDIR/$SRCFILE
+}
+
+
+create_aliases()
+{
+SRCFILE=aliases
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Replace first " " with ": " to make it similar to aliases
+sed 's/ /: /' $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.sed
+
+# Sort aliases entries alphabetically
+sort $TMPDIR/${MAP}.sed > $OUTDIR/$SRCFILE
+}
+
+
+create_publickey()
+{
+SRCFILE=publickey
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Sort entries alphabetically
+sort $TMPDIR/${MAP}.grep > $OUTDIR/$SRCFILE
+}
+
+
+create_netid()
+{
+SRCFILE=netid
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# netid source files is used to add other domain
+# entries. So, filter out local domain entries
+grep -v "@${DOMAIN}" $TMPDIR/${MAP}.grep > $OUTDIR/$SRCFILE
+}
+
+
+create_netmasks()
+{
+SRCFILE=netmasks
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Sort the network numbers in ascending order
+sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4 $TMPDIR/${MAP}.grep > $OUTDIR/$SRCFILE
+}
+
+
+create_passwd_adjunct()
+{
+SRCFILE=passwd.adjunct
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines. It has three of them.
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME | grep -v YP_SECURE > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+## Check if sorting is ok, or leave it as it is.
+# Sort the entries in alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_group_adjunct()
+{
+SRCFILE=group.adjunct
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines. It has three of them.
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME | grep -v YP_SECURE > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort the entries in alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_timezone()
+{
+SRCFILE=timezone
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort the entries in alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_auto_src()
+{
+SRCFILE=$MAP
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Sort entries alphabetically
+sort $TMPDIR/${MAP}.grep > $OUTDIR/$SRCFILE
+}
+
+
+create_auth_attr()
+{
+SRCFILE=auth_attr
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort entries in the alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_exec_attr()
+{
+SRCFILE=exec_attr
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key which is made of three fields. space is part of key
+cut -f 3- -d ":" $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut1
+cut -f 2- -d " " $TMPDIR/${MAP}.cut1 > $TMPDIR/${MAP}.cut2
+
+# Sort entries in the alphabetical order
+sort $TMPDIR/${MAP}.cut2 > $OUTDIR/$SRCFILE
+}
+
+
+create_prof_attr()
+{
+SRCFILE=prof_attr
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key. It is difficult here as space is part of the key.
+# From the "key key" part, extract "key", and then paste it with
+# the rest of the entry.
+cut -f1 -d: $TMPDIR/${MAP}.grep |
+awk '{
+ STR = $1
+ for (i=2; i <= NF/2; i++) {
+ STR = STR " " $i
+ }
+print STR
+}' > $TMPDIR/${MAP}.cut1
+
+cut -f2- -d: $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut2
+paste -d ":" $TMPDIR/${MAP}.cut1 $TMPDIR/${MAP}.cut2 > $TMPDIR/${MAP}.cut
+
+# Sort entries in the alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_user_attr()
+{
+SRCFILE=user_attr
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort entries in the alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+create_audit_user()
+{
+SRCFILE=audit_user
+
+makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines. It has 3 of them.
+grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME | grep -v YP_SECURE > $TMPDIR/${MAP}.grep
+
+# Remove the key
+cut -f 2- -d " " $TMPDIR/${MAP}.grep > $TMPDIR/${MAP}.cut
+
+# Sort entries in the alphabetical order
+sort $TMPDIR/${MAP}.cut > $OUTDIR/$SRCFILE
+}
+
+
+## MAIN ##
+
+PROG=`basename $0`
+
+# Only root can read the NIS maps, so no point allowing
+# non-root users to be able to run this script.
+is_root_user
+if [ $? -ne 0 ]; then
+ echo "ERROR : Only root can run $PROG"
+ exit 1
+fi
+
+# Prevent non-root users from reading/writing
+umask 077
+
+# Initialize default values.
+DOMAIN=`/usr/bin/domainname`
+MAPDIR=/var/yp/"$DOMAIN" # Default to local domain
+N2LPREFIX=LDAP_
+
+NIS_ONLY_MAP_LIST="passwd.byuid
+ group.byname
+ hosts.byaddr
+ ipnodes.byaddr
+ ethers.byname
+ networks.byaddr
+ rpc.bynumber
+ services.byname
+ protocols.bynumber
+ netgroup
+ bootparams
+ mail.aliases
+ publickey.byname
+ netid.byname
+ netmasks.byaddr
+ passwd.adjunct.byname
+ group.adjunct.byname
+ timezone.byname
+ auth_attr
+ exec_attr
+ prof_attr
+ user_attr
+ audit_user"
+
+NIS2LDAP_MAP_LIST="${N2LPREFIX}passwd.byuid
+ ${N2LPREFIX}group.byname
+ ${N2LPREFIX}hosts.byaddr
+ ${N2LPREFIX}ipnodes.byaddr
+ ${N2LPREFIX}ethers.byname
+ ${N2LPREFIX}networks.byaddr
+ ${N2LPREFIX}rpc.bynumber
+ ${N2LPREFIX}services.byname
+ ${N2LPREFIX}protocols.bynumber
+ ${N2LPREFIX}netgroup
+ ${N2LPREFIX}bootparams
+ ${N2LPREFIX}mail.aliases
+ ${N2LPREFIX}publickey.byname
+ ${N2LPREFIX}netid.byname
+ ${N2LPREFIX}netmasks.byaddr
+ ${N2LPREFIX}passwd.adjunct.byname
+ ${N2LPREFIX}group.adjunct.byname
+ ${N2LPREFIX}timezone.byname
+ ${N2LPREFIX}auth_attr
+ ${N2LPREFIX}exec_attr
+ ${N2LPREFIX}prof_attr
+ ${N2LPREFIX}user_attr
+ ${N2LPREFIX}audit_user"
+
+
+# If auto maps exist, add them to the respective lists.
+for dbmfile in $MAPDIR/auto.*.dir
+do
+ MAP=`basename $dbmfile .dir`
+ if [ -f $MAPDIR/${MAP}.pag ]; then
+ NIS_ONLY_MAP_LIST="$NIS_ONLY_MAP_LIST $MAP"
+ fi
+done
+
+for dbmfile in $MAPDIR/${N2LPREFIX}auto.*.dir
+do
+ MAP=`basename $dbmfile .dir`
+ if [ -f $MAPDIR/${MAP}.pag ]; then
+ NIS2LDAP_MAP_LIST="$NIS2LDAP_MAP_LIST $MAP"
+ fi
+done
+
+# Default to N2L maps
+MAP_LIST="$NIS2LDAP_MAP_LIST"
+
+# Safe place to avoid anyone from reading sensitive data.
+TMPDIR="/var/tmp/ypmap2src"
+
+DEBUG=0 # Default to debug off
+DEBUG=1
+OUTDIR=""
+CUST_MAP_LIST=""
+CMDLINE_SRCS=0
+
+
+parse_argument $*
+
+[ $DEBUG -eq 1 ] && echo DOMAIN = $DOMAIN
+[ $DEBUG -eq 1 ] && echo OUTDIR = $OUTDIR
+[ $DEBUG -eq 1 ] && echo TMPDIR = $TMPDIR
+[ $DEBUG -eq 1 ] && echo CUST_MAP_LIST = $CUST_MAP_LIST
+[ $DEBUG -eq 1 ] && echo MAP_LIST = $MAP_LIST
+
+[ $DEBUG -eq 1 ] && echo MAPDIR = $MAPDIR
+if [ ! -d "$MAPDIR" ]; then
+ echo ERROR : NIS Map directory $MAPDIR does not exist.
+ exit 1
+fi
+
+if [ ! -d "$OUTDIR" ]; then
+ echo output directory $OUTDIR does not exist. Creating it.
+ mkdir -p $OUTDIR
+ if [ $? -ne 0 ]; then
+ echo ERROR : Failed to create output directory $OUTDIR
+ exit 1
+ fi
+fi
+
+# Cleanup if the temp directory has been leftover
+[ -d "$TMPDIR" ] && rm -rf $TMPDIR
+mkdir $TMPDIR
+if [ $? -ne 0 ]; then
+ echo ERROR : Failed to create temp directory $TMPDIR
+ exit 1
+fi
+
+
+for MAP in $MAP_LIST
+do
+ [ $DEBUG -eq 1 ] && echo Processing MAP = $MAP
+
+ if [ ! -f $MAPDIR/${MAP}.dir ] || [ ! -f $MAPDIR/${MAP}.pag ]; then
+
+ [ $CMDLINE_SRCS -ne 0 ] && \
+ echo ERROR : Missing DBM file for $MAP in $MAPDIR . Skipping..
+
+ [ $DEBUG -eq 1 ] && [ $CMDLINE_SRCS -eq 0 ] && \
+ echo No DBM file for $MAP in $MAPDIR . Skipping..
+ continue
+ fi
+
+ case $MAP in
+ ${N2LPREFIX}passwd.byuid )
+ create_passwd
+ ;;
+ ${N2LPREFIX}group.byname )
+ create_group
+ ;;
+ ${N2LPREFIX}hosts.byaddr )
+ create_hosts
+ ;;
+ ${N2LPREFIX}ipnodes.byaddr )
+ create_ipnodes
+ ;;
+ ${N2LPREFIX}ethers.byname )
+ create_ethers
+ ;;
+ ${N2LPREFIX}networks.byaddr )
+ create_networks
+ ;;
+ ${N2LPREFIX}rpc.bynumber )
+ create_rpc
+ ;;
+ ${N2LPREFIX}services.byname )
+ create_services
+ ;;
+ ${N2LPREFIX}protocols.bynumber )
+ create_protocols
+ ;;
+ ${N2LPREFIX}netgroup )
+ create_netgroup
+ ;;
+ ${N2LPREFIX}bootparams )
+ create_bootparams
+ ;;
+ ${N2LPREFIX}mail.aliases )
+ create_aliases
+ ;;
+ ${N2LPREFIX}publickey.byname )
+ create_publickey
+ ;;
+ ${N2LPREFIX}netid.byname )
+ create_netid
+ ;;
+ ${N2LPREFIX}netmasks.byaddr )
+ create_netmasks
+ ;;
+ ${N2LPREFIX}passwd.adjunct.byname )
+ create_passwd_adjunct
+ ;;
+ ${N2LPREFIX}group.adjunct.byname )
+ create_group_adjunct
+ ;;
+ ${N2LPREFIX}timezone.byname )
+ create_timezone
+ ;;
+ ${N2LPREFIX}auto.* )
+ create_auto_src
+ ;;
+ ${N2LPREFIX}auth_attr )
+ create_auth_attr
+ ;;
+ ${N2LPREFIX}exec_attr )
+ create_exec_attr
+ ;;
+ ${N2LPREFIX}prof_attr )
+ create_prof_attr
+ ;;
+ ${N2LPREFIX}user_attr )
+ create_user_attr
+ ;;
+ ${N2LPREFIX}audit_user )
+ create_audit_user
+ ;;
+ *) # Not a default map, could be a custom map.
+ CUST_MAP_LIST="$CUST_MAP_LIST $MAP"
+ ;;
+ esac
+done
+
+
+for MAP in $CUST_MAP_LIST
+do
+ [ $DEBUG -eq 1 ] && echo Processing Custom MAP = $MAP
+
+ if [ ! -f $MAPDIR/${MAP}.dir ] || [ ! -f $MAPDIR/${MAP}.pag ]; then
+ echo ERROR : Missing DBM file for $MAP in $MAPDIR . Skipping..
+ continue
+ fi
+
+ makedbm -u $MAPDIR/$MAP > $TMPDIR/$MAP
+
+# Remove the YP operational lines. Assuming each custom map
+# has only these entries (three in n2l mode as shown below, and
+# two in vanilla NIS mode as it does not have "YP_DOMAIN_NAME".
+# But that does not require any changes in the code). Modify it
+# appropriately in other cases.
+
+ grep -v YP_LAST_MODIFIED $TMPDIR/$MAP |
+ grep -v "YP_DOMAIN_NAME $DOMAIN" |
+ grep -v YP_MASTER_NAME > $TMPDIR/${MAP}.grep
+
+# If further processing (e.g., removing key, sorting etc.)
+# is required, then update the script appropriately.
+ cp $TMPDIR/${MAP}.grep $OUTDIR/$MAP
+
+done
+
+# Leave the temp directory if debug is set
+[ $DEBUG -eq 0 ] && rm -rf $TMPDIR
+
+exit 0
diff --git a/usr/src/cmd/ypcmd/yp_b.h b/usr/src/cmd/ypcmd/yp_b.h
new file mode 100644
index 0000000000..f8e5f25c80
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp_b.h
@@ -0,0 +1,192 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ident "%Z%%M% %I% %E% SMI"
+
+#include <rpc/types.h>
+#include "netconfig.h"
+#include <stdio.h>
+
+extern bool_t xdr_netconfig();
+
+#define BINDING "/var/yp/binding"
+
+#define YPSETNONE 0
+#define YPSETLOCAL 3
+#define YPSETALL 5
+
+/*
+ * This structure is used only in the ypxfr protocol and has
+ * nothing to do with ypbind.
+ */
+
+struct dom_binding {
+ struct dom_binding *dom_pnext;
+ char *dom_domain;
+ struct ypbind_binding *dom_binding;
+ CLIENT *dom_client;
+};
+
+/* Following structure is used only by ypbind */
+
+struct domain {
+ struct domain *dom_pnext;
+ char *dom_name;
+ bool_t dom_boundp;
+ unsigned short dom_vers; /* only YPVERS */
+ unsigned long dom_error;
+ CLIENT * ping_clnt;
+ struct ypbind_binding *dom_binding;
+ int dom_report_success; /* Controls msg to /dev/console*/
+ int dom_broadcaster_pid;
+ int bindfile; /* File with binding info in it */
+ int broadcaster_fd;
+ FILE *broadcaster_pipe; /* to get answer from locater */
+ XDR broadcaster_xdr; /* xdr for pipe */
+ struct timeval lastping; /* info to avoid a ping storm */
+ FILE *cache_fp; /* file pointer opened on cache_file */
+ char *cache_file; /* cached version of server info */
+};
+
+enum ypbind_resptype {
+ YPBIND_SUCC_VAL = 1,
+ YPBIND_FAIL_VAL = 2
+};
+typedef enum ypbind_resptype ypbind_resptype;
+bool_t xdr_ypbind_resptype();
+#define YPBIND_ERR_ERR 1 /* Internal error */
+#define YPBIND_ERR_NOSERV 2 /* No bound server for passed domain */
+#define YPBIND_ERR_RESC 3 /* System resource allocation failure */
+#define YPBIND_ERR_NODOMAIN 4 /* Domain doesn't exist */
+
+/* Following struct is used only by ypwhich and yppoll */
+
+struct ypbind_domain {
+ char *ypbind_domainname;
+ long ypbind_vers;
+};
+typedef struct ypbind_domain ypbind_domain;
+bool_t xdr_ypbind_domain();
+
+/*
+ * This structure is used to store information about the server
+ * Returned by ypbind to the libnsl/yp clients to contact ypserv.
+ * Also used by ypxfr.
+ */
+
+struct ypbind_binding {
+ struct netconfig *ypbind_nconf;
+ struct netbuf *ypbind_svcaddr;
+ char *ypbind_servername;
+ long ypbind_hi_vers;
+ long ypbind_lo_vers;
+};
+typedef struct ypbind_binding ypbind_binding;
+bool_t xdr_ypbind_binding();
+
+struct ypbind_resp {
+ ypbind_resptype ypbind_status;
+ union {
+ u_long ypbind_error;
+ struct ypbind_binding *ypbind_bindinfo;
+ } ypbind_resp_u;
+};
+typedef struct ypbind_resp ypbind_resp;
+bool_t xdr_ypbind_resp();
+
+struct ypbind_setdom {
+ char *ypsetdom_domain;
+ struct ypbind_binding *ypsetdom_bindinfo;
+};
+typedef struct ypbind_setdom ypbind_setdom;
+bool_t xdr_ypbind_setdom();
+
+#define YPBINDPROG ((u_long)100007)
+#define YPBINDVERS ((u_long)3)
+#define YPBINDPROC_NULL ((u_long)0)
+extern void *ypbindproc_null_3();
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern ypbind_resp *ypbindproc_domain_3();
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern void *ypbindproc_setdom_3();
+
+
+/*
+ * XXX - compiled and edited from yp.x
+ * These structures are added here to
+ * support binary compatibility with static
+ * apps that use the old ypbind protocol.
+ * These structures are lifted from
+ * 4.x source lib/libc/yp/yp_prot.h
+ * and rename with a suffix _2 to avoid
+ * conflicts with similar structs for
+ * native ypbind protocol, as above.
+ */
+
+typedef char *domainname_2;
+
+struct ypbind_binding_2 {
+ struct in_addr ypbind_binding_addr; /* In network order */
+ unsigned short int ypbind_binding_port; /* In network order */
+};
+typedef struct ypbind_binding_2 ypbind_binding_2;
+
+struct ypbind_resp_2 {
+ ypbind_resptype ypbind_status;
+ union {
+ unsigned long ypbind_error;
+ ypbind_binding_2 ypbind_bindinfo;
+ } ypbind_respbody_2;
+};
+typedef struct ypbind_resp_2 ypbind_resp_2;
+
+struct ypbind_setdom_2 {
+ char ypsetdom_domain[YPMAXDOMAIN + 1];
+ ypbind_binding_2 ypsetdom_binding;
+ unsigned short ypsetdom_vers;
+};
+typedef struct ypbind_setdom_2 ypbind_setdom_2;
+
+/*
+ * ypbind V2 and ypbind V1 differ only in the "set domain"
+ * procedure, which we don't support.
+ */
+#define YPBINDVERS_2 ((unsigned long)(2))
+#define YPBINDVERS_1 ((unsigned long)(1))
+extern ypbind_resp_2 * ypbindproc_domain_2();
+extern int ypbindprog_2_freeresult();
+
+/* the xdr functions */
+extern bool_t xdr_ypbind_binding_2();
+extern bool_t xdr_ypbind_resp_2();
diff --git a/usr/src/cmd/ypcmd/yp_b_subr.c b/usr/src/cmd/ypcmd/yp_b_subr.c
new file mode 100644
index 0000000000..9d5d68bba2
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp_b_subr.c
@@ -0,0 +1,1511 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "ypsym.h"
+#include <stdlib.h>
+#include "yp_b.h"
+#include <string.h>
+#include <limits.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <rpc/clnt.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/statvfs.h>
+#include <rpcsvc/nis.h>
+#include <sys/systeminfo.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define YPSERVERS "ypservers"
+
+void ypbind_init_default();
+static int ypbind_pipe_setdom();
+
+static bool firsttime = TRUE;
+static struct domain *known_domains;
+
+extern struct netconfig *__rpc_getconf();
+extern void *__rpc_setconf(), *__rpc_endconf();
+extern CLIENT *__clnt_tp_create_bootstrap();
+extern char *inet_ntoa();
+extern int __rpc_get_local_uid();
+
+extern listofnames *names();
+extern void free_listofnames();
+
+#define PINGTIME 10 /* Timeout for the ypservers list */
+#define PINGTOTTIM 5 /* Total seconds for ping timeout */
+
+static void broadcast_setup();
+static void sigcld_handler();
+static struct ypbind_binding *dup_ypbind_binding();
+static struct netbuf *dup_netbuf();
+static void free_ypbind_binding();
+static void enable_exit();
+static void ypbind_ping();
+static struct domain *ypbind_point_to_domain();
+static bool ypbind_broadcast_ack();
+static int pong_servers();
+void cache_binding();
+void uncache_binding();
+
+extern int setok;
+extern int broadcast;
+extern int cache_okay;
+
+/*
+ * Need to differentiate between RPC_UNKNOWNHOST returned by the RPC
+ * library, and the same error caused by a local lookup failure in
+ * /etc/hosts and/or /etc/inet/ipnodes.
+ */
+int hostNotKnownLocally;
+
+/*ARGSUSED*/
+void *
+ypbindproc_null_3(argp, clnt)
+void *argp;
+CLIENT *clnt;
+{
+ static char res;
+
+ return ((void *) & res);
+}
+
+static void
+enable_exit()
+{
+ static bool done = FALSE;
+
+ if (!done) {
+ done = TRUE;
+ sigset(SIGCHLD, (void (*)())sigcld_handler);
+ }
+}
+
+int sigcld_event = 0;
+
+static void
+sigcld_handler()
+{
+ sigcld_event++;
+#ifdef DEBUG
+ fprintf(stderr, "ypbind sighandler: got SIGCLD signal (event=%d)\n",
+ sigcld_event);
+#endif
+}
+
+
+/*
+ * This is a Unix SIGCHILD handler that notices when a broadcaster child
+ * process has exited, and retrieves the exit status. The broadcaster pid
+ * is set to 0. If the broadcaster succeeded, dom_report_success will be
+ * be set to -1.
+ */
+
+void
+broadcast_proc_exit()
+{
+ int pid, ret;
+ siginfo_t infop;
+ register struct domain *pdom;
+ bool succeeded = FALSE;
+
+ sigcld_event = 0;
+ /* ==== Why WEXITED? */
+ while ((ret = waitid(P_ALL, 0, &infop, WNOHANG | WEXITED)) != -1) {
+ switch (infop.si_code) {
+ case CLD_EXITED:
+ succeeded = infop.si_status == 0;
+ break;
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ succeeded = FALSE;
+ break;
+ case CLD_TRAPPED:
+ case CLD_STOPPED:
+ case CLD_CONTINUED:
+ enable_exit();
+ return;
+ }
+ pid = infop.si_pid;
+
+#ifdef DEBUG
+ fprintf(stderr,
+ "ypbind event_handler: got wait from %d status = %d\n",
+ pid, infop.si_status);
+#endif
+
+ /* to aid the progeny print the infamous "not responding" message */
+ firsttime = FALSE;
+
+ for (pdom = known_domains; pdom != (struct domain *)NULL;
+ pdom = pdom->dom_pnext) {
+
+ if (pdom->dom_broadcaster_pid == pid) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "ypbind event_handler: got match %s\n", pdom->dom_name);
+#endif
+ if (succeeded) {
+ broadcast_setup(pdom);
+ }
+ if (pdom->broadcaster_pipe != 0) {
+ xdr_destroy(&(pdom->broadcaster_xdr));
+ fclose(pdom->broadcaster_pipe);
+ pdom->broadcaster_pipe = 0;
+ pdom->broadcaster_fd = -1;
+ }
+ pdom->dom_broadcaster_pid = 0;
+
+ break;
+ }
+ }
+ } /* while loop */
+ enable_exit();
+}
+
+static void
+broadcast_setup(pdom)
+struct domain *pdom;
+{
+ ypbind_setdom req;
+
+ memset(&req, 0, sizeof (req));
+ if (pdom->broadcaster_pipe) {
+ pdom->dom_report_success = -1;
+ if (xdr_ypbind_setdom(&(pdom->broadcaster_xdr), &req)) {
+#ifdef DEBUG
+ fprintf(stderr, "parent: broadcast_setup: got xdr ok \n");
+#endif
+ ypbindproc_setdom_3(&req, (struct svc_req *)NULL,
+ (SVCXPRT *)NULL);
+ xdr_free(xdr_ypbind_setdom, (char *)&req);
+ gettimeofday(&(pdom->lastping), NULL);
+ }
+#ifdef DEBUG
+ else {
+ fprintf(stderr, "ypbind parent: xdr_ypbind_setdom failed\n");
+ }
+#endif
+ }
+#ifdef DEBUG
+ else {
+ fprintf(stderr, "ypbind: internal error -- no broadcaster pipe\n");
+ }
+#endif
+}
+
+#define YPBIND_PINGHOLD_DOWN 5
+/* Same as the ypbind_get_binding() routine in SunOS */
+/*ARGSUSED*/
+ypbind_resp *
+ypbindproc_domain_3(argp, clnt)
+ypbind_domain *argp;
+CLIENT *clnt;
+{
+ static ypbind_resp resp;
+ struct domain *cur_domain;
+ int bpid;
+ int fildes[2];
+
+ memset((char *)&resp, 0, sizeof (resp));
+
+#ifdef DEBUG
+ fprintf(stderr, "\nypbindproc_domain_3: domain: %s\n",
+ argp->ypbind_domainname);
+#endif
+
+ if ((int)strlen(argp->ypbind_domainname) > YPMAXDOMAIN) {
+
+ resp.ypbind_status = YPBIND_FAIL_VAL;
+ resp.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV;
+ return (&resp);
+ }
+
+ if ((cur_domain = ypbind_point_to_domain(argp->ypbind_domainname)) !=
+ (struct domain *)NULL) {
+ if (cur_domain->dom_boundp) {
+
+ struct timeval tp;
+
+ (void) gettimeofday(&tp, NULL);
+ if ((tp.tv_sec - cur_domain->lastping.tv_sec) >
+ YPBIND_PINGHOLD_DOWN) {
+#ifdef DEBUG
+ fprintf(stderr, "domain is bound pinging: %s\n",
+ argp->ypbind_domainname);
+#endif
+ (void) ypbind_ping(cur_domain);
+ }
+ }
+
+ /*
+ * Bound or not, return the current state of the binding.
+ */
+
+ if (cur_domain->dom_boundp) {
+#ifdef DEBUG
+ fprintf(stderr, "server is up for domain: %s\n",
+ argp->ypbind_domainname);
+#endif
+ resp.ypbind_status = YPBIND_SUCC_VAL;
+ resp.ypbind_resp_u.ypbind_bindinfo =
+ cur_domain->dom_binding;
+ } else {
+#ifdef DEBUG
+ fprintf(stderr, "domain is NOT bound returning: %s %d\n",
+ argp->ypbind_domainname, cur_domain->dom_error);
+#endif
+ resp.ypbind_status = YPBIND_FAIL_VAL;
+ resp.ypbind_resp_u.ypbind_error =
+ cur_domain->dom_error;
+ }
+
+ } else {
+ resp.ypbind_status = YPBIND_FAIL_VAL;
+ resp.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC;
+ }
+ /*
+ * RETURN NOW: if successful, otherwise
+ * RETURN LATER: after spawning off a child to do the "broadcast" work.
+ */
+ if (resp.ypbind_status == YPBIND_SUCC_VAL) {
+#ifdef DEBUG
+ fprintf(stderr, "yp_b_subr: returning success to yp_b_svc %d\n",
+ resp.ypbind_status);
+#endif
+ return (&resp);
+ }
+
+ /* Go about the broadcast (really, pinging here) business */
+
+ if ((cur_domain) && (!cur_domain->dom_boundp) &&
+ (!cur_domain->dom_broadcaster_pid)) {
+#ifdef DEBUG
+ fprintf(stderr, "yp_b_subr: fork: boundp=%d broadcast_pid=%d\n",
+ cur_domain->dom_boundp, cur_domain->dom_broadcaster_pid);
+#endif
+ /*
+ * The current domain is unbound, and there is no child
+ * process active now. Fork off a child who will beg to the
+ * ypservers list one by one or broadcast and accept whoever
+ * commands the right domain.
+ */
+ if (pipe(fildes) < 0) {
+#ifdef DEBUG
+ fprintf(stderr, "yp_b_subr: returning pipe failure to yp_b_svc %d\n",
+ resp.ypbind_status);
+#endif
+ return (&resp);
+ }
+
+ enable_exit();
+ sighold(SIGCLD); /* add it to ypbind's signal mask */
+ cur_domain->dom_report_success++;
+ bpid = fork();
+ if (bpid != 0) { /* parent */
+ if (bpid > 0) { /* parent started */
+ close(fildes[1]);
+ cur_domain->dom_broadcaster_pid = bpid;
+ cur_domain->broadcaster_fd = fildes[0];
+ cur_domain->broadcaster_pipe =
+ fdopen(fildes[0], "r");
+ if (cur_domain->broadcaster_pipe)
+ xdrstdio_create(&(cur_domain->broadcaster_xdr),
+ (cur_domain->broadcaster_pipe), XDR_DECODE);
+
+#ifdef DEBUG
+ fprintf(stderr, "ypbindproc_domain_3: %s starting pid = %d try = %d\n",
+ cur_domain->dom_name, bpid,
+ cur_domain->dom_report_success);
+ fprintf(stderr, "yp_b_subr: returning after spawning, to yp_b_svc %d\n",
+ resp.ypbind_status);
+#endif
+ sigrelse(SIGCLD);
+ /* remove it from ypbind's signal mask */
+ return (&resp);
+ } else { /* fork failed */
+ perror("fork");
+ close(fildes[0]);
+ close(fildes[1]);
+#ifdef DEBUG
+ fprintf(stderr, "yp_b_subr: returning fork failure to yp_b_svc %d\n",
+ resp.ypbind_status);
+#endif
+ sigrelse(SIGCLD);
+ return (&resp);
+ }
+ } /* end parent */
+ /* child only code */
+ sigrelse(SIGCLD);
+ close(fildes[0]);
+ cur_domain->broadcaster_fd = fildes[1];
+ cur_domain->broadcaster_pipe = fdopen(fildes[1], "w");
+ if (cur_domain->broadcaster_pipe)
+ xdrstdio_create(&(cur_domain->broadcaster_xdr),
+ (cur_domain->broadcaster_pipe), XDR_ENCODE);
+ else {
+ perror("fdopen-pipe");
+ exit(-1);
+ }
+ exit(pong_servers(cur_domain));
+ }
+#ifdef DEBUG
+ fprintf(stderr, "yp_b_subr: lazy returns failure status yp_b_svc %d\n",
+ resp.ypbind_status);
+#endif
+ return (&resp);
+}
+
+
+/*
+ * call ypbindproc_domain_3 and convert results
+ *
+ * This adds support for YP clients that send requests on
+ * ypbind version 1 & 2 (i.e. clients before we started
+ * using universal addresses and netbufs). This is supported
+ * for binary compatibility for static 4.x programs. The
+ * assumption used to be that clients coming in with ypbind vers 1
+ * should be given the address of a server serving ypserv version 1.
+ * However, since yp_bind routines in 4.x YP library try
+ * to connect with ypserv version 2, even if they requested
+ * binding using ypbind version 1, the ypbind process will
+ * "always" look for only ypserv version 2 servers for all
+ * (ypbind vers 1, 2, & 3) clients.
+ */
+ypbind_resp_2 *
+ypbindproc_domain_2(argp, clnt)
+domainname_2 *argp;
+CLIENT *clnt;
+{
+ ypbind_domain arg_3;
+ ypbind_resp *resp_3;
+ static ypbind_resp_2 resp;
+
+ arg_3.ypbind_domainname = *argp;
+ resp_3 = ypbindproc_domain_3(&arg_3, clnt);
+ if (resp_3 == NULL)
+ return (NULL);
+ resp.ypbind_status = resp_3->ypbind_status;
+ if (resp_3->ypbind_status == YPBIND_SUCC_VAL) {
+ struct sockaddr_in *sin;
+ struct ypbind_binding_2 *bi;
+
+ sin = (struct sockaddr_in *)
+ resp_3->ypbind_resp_u.ypbind_bindinfo->ypbind_svcaddr->buf;
+ if (sin->sin_family == AF_INET) {
+ bi = &resp.ypbind_respbody_2.ypbind_bindinfo;
+ memcpy(&(bi->ypbind_binding_port), &sin->sin_port, 2);
+ memcpy(&(bi->ypbind_binding_addr), &sin->sin_addr, 4);
+ } else {
+ resp.ypbind_respbody_2.ypbind_error = YPBIND_ERR_NOSERV;
+ }
+ } else {
+ resp.ypbind_respbody_2.ypbind_error =
+ resp_3->ypbind_resp_u.ypbind_error;
+ }
+ return (&resp);
+}
+
+/* used to exchange information between pong_servers and ypbind_broadcast_ack */
+struct domain *process_current_domain;
+
+int
+pong_servers(domain_struct)
+struct domain *domain_struct; /* to pass back */
+{
+ char *domain = domain_struct->dom_name;
+ CLIENT *clnt2;
+ char *servername;
+ listofnames *list, *lin;
+ char serverfile[MAXNAMLEN];
+ struct timeval timeout;
+ int isok = 0, res = -1;
+ struct netconfig *nconf;
+ void *handle;
+ int nconf_count;
+ char rpcdomain[YPMAXDOMAIN+1];
+ long inforet;
+
+ /*
+ * If the ``domain'' name passed in is not the same as the RPC
+ * domain set from /etc/defaultdomain. Then we set ``firsttime''
+ * to TRUE so no error messages are ever syslog()-ed this
+ * prevents a possible Denial of Service attack.
+ */
+ inforet = sysinfo(SI_SRPC_DOMAIN, &(rpcdomain[0]), YPMAXDOMAIN);
+ if ((inforet > 0) && (strcmp(domain, rpcdomain) != 0))
+ firsttime = TRUE;
+
+ if (broadcast) {
+ enum clnt_stat stat = RPC_SUCCESS;
+#ifdef DEBUG
+ fprintf(stderr, "pong_servers: doing an rpc_broadcast\n");
+#endif
+ /*
+ * Here we do the real SunOS thing that users love. Do a
+ * broadcast on the network and find out the ypserv. No need
+ * to do "ypinit -c", no setting up /etc/hosts file, and no
+ * recursion looking up the server's IP address.
+ */
+ process_current_domain = domain_struct;
+ stat = rpc_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK,
+ (xdrproc_t)xdr_ypdomain_wrap_string, (caddr_t)&domain,
+ xdr_int, (caddr_t)&isok,
+ (resultproc_t)ypbind_broadcast_ack, "udp");
+ if (stat == RPC_SYSTEMERROR || stat == RPC_UNKNOWNPROTO ||
+ stat == RPC_CANTRECV || stat == RPC_CANTSEND ||
+ stat == RPC_NOBROADCAST ||
+ stat == RPC_N2AXLATEFAILURE) {
+ syslog(LOG_ERR, "RPC/Transport subsystem failure %s\n",
+ clnt_sperrno(stat));
+ exit(-1);
+ }
+ if (domain_struct->broadcaster_pipe == 0)
+ /* init binding case */
+ return (domain_struct->dom_boundp - 1);
+ if (domain_struct->dom_boundp) {
+ res = ypbind_pipe_setdom(NULL, domain,
+ NULL, domain_struct);
+ if (domain_struct->dom_report_success > 0)
+ syslog(LOG_ERR,
+ "NIS server for domain \"%s\" OK", domain);
+ } else if (firsttime == FALSE)
+ syslog(LOG_ERR,
+ "NIS server not responding for domain \"%s\"; still trying", domain);
+ return (res);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "pong_servers: ponging servers one by one\n");
+#endif
+ /*
+ * Do the politically correct thing.. transport independent and
+ * secure (trusts only listed servers).
+ */
+
+ /*
+ * get list of possible servers for this domain
+ */
+
+ /*
+ * get alias for domain: Things of the past..
+ * sysvconfig();
+ * (void) yp_getalias(domain, domain_alias, NAME_MAX);
+ */
+ sprintf(serverfile, "%s/%s/%s", BINDING, domain, YPSERVERS);
+#ifdef DEBUG
+ fprintf(stderr, "pong_servers: serverfile %s\n", serverfile);
+#endif
+ list = names(serverfile);
+ if (list == NULL) {
+ if (firsttime == FALSE)
+ syslog(LOG_ERR,
+ "service not installed, use /usr/sbin/ypinit -c");
+ return (-1);
+ }
+ lin = list;
+ for (list = lin; list; list = list->nextname) {
+ servername = strtok(list->name, " \t\n");
+ if (servername == NULL) continue;
+
+ /* Check all datagram_v transports for this server */
+ if ((handle = __rpc_setconf("datagram_v")) == NULL) {
+ syslog(LOG_ERR,
+ "ypbind: RPC operation on /etc/netconfig failed");
+ free_listofnames(lin);
+ return (-1);
+ }
+
+ nconf_count = 0;
+ clnt2 = 0;
+ while (clnt2 == 0 && (nconf = __rpc_getconf(handle)) != 0) {
+ nconf_count++;
+ /*
+ * We use only datagram here. It is expected to be udp.
+ * VERY IMPORTANT: __clnt_tp_create_bootstrap is a
+ * hacked up version that does not do netdir_getbyname.
+ */
+ hostNotKnownLocally = 0;
+ clnt2 =
+ __clnt_tp_create_bootstrap(servername, YPPROG, YPVERS, nconf);
+ }
+ if (nconf_count == 0) {
+ syslog(LOG_ERR,
+ "ypbind: RPC operation on /etc/netconfig failed");
+ free_listofnames(lin);
+ return (-1);
+ }
+
+ if (clnt2 == 0) {
+ if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST &&
+ hostNotKnownLocally) {
+ syslog(LOG_ERR,
+ "NIS server %s is not in local host files !", servername);
+ }
+ perror(servername);
+ clnt_pcreateerror("ypbind");
+ continue;
+ }
+
+ timeout.tv_sec = PINGTIME;
+ timeout.tv_usec = 0;
+ if ((enum clnt_stat) clnt_call(clnt2,
+ YPPROC_DOMAIN, (xdrproc_t)xdr_ypdomain_wrap_string,
+ (char *)&domain, xdr_int,
+ (char *)&isok, timeout) == RPC_SUCCESS) {
+ if (isok) {
+ if (domain_struct->dom_report_success > 0) {
+ syslog(LOG_ERR,
+ "NIS server for domain \"%s\" OK", domain);
+ }
+ if (domain_struct->broadcaster_pipe == 0) {
+ /* init binding case --parent */
+ struct netconfig *setnc;
+ struct netbuf setua;
+ struct ypbind_binding *b =
+ domain_struct->dom_binding;
+
+ setnc =
+ getnetconfigent(clnt2->cl_netid);
+ if (b == NULL) {
+ /* ASSERT: This shouldn't happen ! */
+ b =
+ (struct ypbind_binding *)calloc(1, sizeof (*b));
+ domain_struct->dom_binding = b;
+ if (b == NULL) {
+ __rpc_endconf(handle);
+ clnt_destroy(clnt2);
+ free_listofnames(lin);
+ return (-2);
+ }
+ }
+
+
+ b->ypbind_nconf = setnc;
+ clnt_control(clnt2, CLGET_SVC_ADDR,
+ (char *)&setua);
+ if (b->ypbind_svcaddr) {
+ if (b->ypbind_svcaddr->buf)
+ free(b->ypbind_svcaddr->buf);
+ free(b->ypbind_svcaddr);
+ }
+ b->ypbind_svcaddr = dup_netbuf(&setua);
+ if (b->ypbind_servername)
+ free(b->ypbind_servername);
+ b->ypbind_servername =
+ strdup(servername);
+ b->ypbind_hi_vers = YPVERS;
+ b->ypbind_lo_vers = YPVERS;
+ __rpc_endconf(handle);
+ domain_struct->dom_boundp = TRUE;
+ clnt_destroy(clnt2);
+ free_listofnames(lin);
+ return (0);
+ }
+ res = ypbind_pipe_setdom(clnt2, domain,
+ servername, domain_struct);
+ __rpc_endconf(handle);
+ clnt_destroy(clnt2);
+ free_listofnames(lin);
+ return (res);
+ } else {
+ syslog(LOG_ERR,
+ "server %s doesn't serve domain %s\n",
+ servername, domain);
+ }
+ } else {
+ clnt_perror(clnt2, servername);
+ }
+ clnt_destroy(clnt2);
+ }
+ /*
+ * We tried all servers, none obliged !
+ * After ypbind is started up it will not be bound
+ * immediately. This is normal, no error message
+ * is needed. Although, with the ypbind_init_default
+ * it will be bound immediately.
+ */
+ if (firsttime == FALSE) {
+ syslog(LOG_ERR,
+"NIS server not responding for domain \"%s\"; still trying", domain);
+ }
+ free_listofnames(lin);
+ __rpc_endconf(handle);
+ return (-2);
+}
+
+struct netbuf *
+dup_netbuf(inbuf)
+ struct netbuf *inbuf;
+{
+ struct netbuf *outbuf;
+
+ if (inbuf == NULL)
+ return (NULL);
+ if ((outbuf =
+ (struct netbuf *)calloc(1, sizeof (struct netbuf))) == NULL)
+ return (NULL);
+ if ((outbuf->buf = malloc(inbuf->len)) == NULL) {
+ free(outbuf);
+ return (NULL);
+ }
+ outbuf->len = inbuf->len;
+ outbuf->maxlen = inbuf->len;
+ (void) memcpy(outbuf->buf, inbuf->buf, inbuf->len);
+ return (outbuf);
+}
+
+/*
+ * This is called by the broadcast rpc routines to process the responses
+ * coming back from the broadcast request. Since the form of the request
+ * which is used in ypbind_broadcast_bind is "respond only in the positive
+ * case", we know that we have a server.
+ * The internet address of the responding server will be picked up from
+ * the saddr parameter, and stuffed into the domain. The domain's boundp
+ * field will be set TRUE. The first responding server (or the first one
+ * which is on a reserved port) will be the bound server for the domain.
+ */
+bool
+ypbind_broadcast_ack(ptrue, nbuf, nconf)
+ bool *ptrue;
+ struct netbuf *nbuf;
+ struct netconfig *nconf;
+{
+ struct ypbind_binding b;
+
+ process_current_domain->dom_boundp = TRUE;
+ b.ypbind_nconf = nconf;
+ b.ypbind_svcaddr = nbuf;
+ b.ypbind_servername = "\000";
+ b.ypbind_hi_vers = YPVERS;
+ b.ypbind_lo_vers = YPVERS;
+ free_ypbind_binding(process_current_domain->dom_binding);
+ process_current_domain->dom_binding = dup_ypbind_binding(&b);
+ return (TRUE);
+}
+
+/*
+ * WARNING: This routine is entered only by the child process.
+ * Called if it pongs/broadcasts okay.
+ */
+static int
+ypbind_pipe_setdom(client, domain, servername, opaque_domain)
+CLIENT *client;
+char *servername;
+char *domain;
+struct domain *opaque_domain;
+{
+ struct netconfig *setnc;
+ struct netbuf setua;
+ ypbind_binding setb;
+ ypbind_setdom setd;
+ int retval;
+
+ setd.ypsetdom_domain = domain;
+ if (client == NULL && opaque_domain->dom_binding) {
+#ifdef DEBUG
+ fprintf(stderr, "ypbind_pipe_setdom: child broadcast case ");
+#endif
+ /* ypbind_broadcast_ack already setup dom_binding for us */
+ setd.ypsetdom_bindinfo = opaque_domain->dom_binding;
+ } else if (client) {
+#ifdef DEBUG
+ fprintf(stderr, "ypbind_pipe_setdom: child unicast case ");
+#endif
+ setnc = getnetconfigent(client->cl_netid);
+ if (setnc == NULL) {
+#ifdef DEBUG
+ fprintf(stderr, "PANIC: shouldn't happen\n");
+#endif
+ fclose(opaque_domain->broadcaster_pipe);
+ close(opaque_domain->broadcaster_fd);
+ return (-2);
+ }
+ clnt_control(client, CLGET_SVC_ADDR, (char *)&setua);
+ setb.ypbind_nconf = setnc;
+ setb.ypbind_svcaddr = &setua;
+ setb.ypbind_servername = servername;
+ setb.ypbind_hi_vers = YPVERS;
+ setb.ypbind_lo_vers = YPVERS;
+ setd.ypsetdom_bindinfo = &setb;
+ /*
+ * Let's hardcode versions, that is the only ypserv we support anyway.
+ * Avoid the song and dance of recursively calling ypbind_ping
+ * for no reason. Consistent with the 4.1 policy, that if ypbind gets
+ * a request on new binder protocol, the requestor is looking for the
+ * new ypserv. And, we have even higher binder protocol version i.e. 3.
+ */
+ } else
+ return (-1);
+#ifdef DEBUG
+ fprintf(stderr,
+ " saving server settings, \nsupports versions %d thru %d\n",
+ setd.ypsetdom_bindinfo->ypbind_lo_vers,
+ setd.ypsetdom_bindinfo->ypbind_hi_vers);
+#endif
+
+ if (opaque_domain->broadcaster_pipe == 0) {
+#ifdef DEBUG
+ fprintf(stderr, "PANIC: shouldn't be in this function\n");
+#endif
+ return (-2);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "child: doing xdr_ypbind_setdom\n");
+#endif
+ retval = xdr_ypbind_setdom(&(opaque_domain->broadcaster_xdr), &setd);
+ xdr_destroy(&(opaque_domain->broadcaster_xdr));
+ fclose(opaque_domain->broadcaster_pipe);
+ close(opaque_domain->broadcaster_fd);
+ /*
+ * This child process is about to exit. Don't bother freeing memory.
+ */
+ if (!retval) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "YPBIND pipe_setdom failed \n(xdr failure) to server %s\n",
+ servername ? servername : "");
+#endif
+ return (-3);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "ypbind_pipe_setdom: YPBIND OK-set to server %s\n",
+ servername ? servername : "");
+#endif
+ return (0);
+}
+
+/* Same as ypbind_set_binding in SunOS */
+/*
+ * We use a trick from SunOS to return an error to the ypset command
+ * when we are not allowing the domain to be set. We do a svcerr_noprog()
+ * to send RPC_PROGUNAVAIL to ypset. We also return NULL so that
+ * our caller (ypbindprog_3) won't try to return a result. This
+ * hack is necessary because the YPBINDPROC_SETDOM procedure is defined
+ * in the protocol to return xdr_void, so we don't have a direct way to
+ * return an error to the client.
+ */
+/*ARGSUSED*/
+void *
+ypbindproc_setdom_3(argp, rqstp, transp)
+ypbind_setdom *argp;
+struct svc_req *rqstp;
+SVCXPRT *transp;
+{
+ struct domain *a_domain;
+ struct netbuf *who;
+ static char res; /* dummy for void * return */
+ uid_t caller_uid;
+
+ if ((int)strlen(argp->ypsetdom_domain) > YPMAXDOMAIN) {
+
+ if (transp) {
+ svcerr_systemerr(transp);
+ return (0);
+ }
+ return (&res);
+ }
+
+ if (transp != NULL) {
+ /* find out who originated the request */
+ char *uaddr;
+ struct netconfig *nconf;
+
+ who = svc_getrpccaller(transp);
+ if ((nconf = getnetconfigent(transp->xp_netid))
+ == (struct netconfig *)NULL) {
+ svcerr_systemerr(transp);
+ return (0);
+ }
+ if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ uaddr = strdup("local host");
+ } else {
+ uaddr = taddr2uaddr(nconf, who);
+ }
+ if (setok != YPSETALL) {
+ /* for -ypset, it falls through and let anybody do a setdom ! */
+ if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0) {
+ syslog(LOG_ERR,
+"ypset request from %s not on loopback, \
+cannot set ypbind to %s", uaddr ? uaddr : "unknown source",
+argp->ypsetdom_bindinfo->ypbind_servername);
+ if (uaddr)
+ free(uaddr);
+ freenetconfigent(nconf);
+ svcerr_noprog(transp);
+ return (0);
+ }
+ switch (setok) {
+ case YPSETNONE:
+ if (strcmp(nconf->nc_protofmly,
+ NC_LOOPBACK) == 0)
+ syslog(LOG_ERR,
+"ypset request to %s from %s failed - ypset not allowed",
+argp->ypsetdom_bindinfo->ypbind_servername, uaddr);
+ if (uaddr)
+ free(uaddr);
+ freenetconfigent(nconf);
+ svcerr_noprog(transp);
+ return (0);
+ case YPSETLOCAL:
+ if (__rpc_get_local_uid(transp,
+ &caller_uid) < 0) {
+ syslog(LOG_ERR, "ypset request from \
+unidentified local user on %s - ypset not allowed",
+transp->xp_netid);
+ if (uaddr)
+ free(uaddr);
+ freenetconfigent(nconf);
+ svcerr_noprog(transp);
+ return (0);
+ }
+ if (caller_uid != 0) {
+ syslog(LOG_ERR,
+"Set domain request to host %s \
+from local non-root user %ld failed - ypset not allowed",
+argp->ypsetdom_bindinfo->ypbind_servername, caller_uid);
+ if (uaddr)
+ free(uaddr);
+ freenetconfigent(nconf);
+ svcerr_noprog(transp);
+ return (0);
+ }
+ }
+ }
+ syslog(LOG_ERR, "Set domain request from %s : \
+setting server for domain %s to %s", uaddr ? uaddr : "UNKNOWN SOURCE",
+argp->ypsetdom_domain, argp->ypsetdom_bindinfo->ypbind_servername);
+ if (uaddr)
+ free(uaddr);
+ freenetconfigent(nconf);
+ }
+
+ if ((a_domain = ypbind_point_to_domain(argp->ypsetdom_domain))
+ != (struct domain *)NULL) {
+ /* setting binding; old may be invalid */
+ uncache_binding(a_domain);
+
+ /* this does the set -- should copy the structure */
+ free_ypbind_binding(a_domain->dom_binding);
+ if ((a_domain->dom_binding =
+ dup_ypbind_binding(argp->ypsetdom_bindinfo)) == NULL) {
+ syslog(LOG_ERR, "ypbindproc_setdom_3: out of memory, ",
+ "dup_ypbind_binding failed\n");
+ if (transp) {
+ svcerr_noprog(transp);
+ return (0);
+ }
+ return (&res);
+ }
+ gettimeofday(&(a_domain->lastping), NULL);
+ a_domain->dom_boundp = TRUE;
+ cache_binding(a_domain);
+#ifdef DEBUG
+ fprintf(stderr, "ypbindproc_setdom_3: setting domain %s to server %s\n",
+ argp->ypsetdom_domain,
+ argp->ypsetdom_bindinfo->ypbind_servername);
+#endif
+ }
+
+ return (&res);
+}
+
+/*
+ * This returns a pointer to a domain entry. If no such domain existed on
+ * the list previously, an entry will be allocated, initialized, and linked
+ * to the list. Note: If no memory can be malloc-ed for the domain structure,
+ * the functional value will be (struct domain *) NULL.
+ */
+static struct domain *
+ypbind_point_to_domain(pname)
+register char *pname;
+{
+ register struct domain *pdom;
+ char buf[300];
+
+ for (pdom = known_domains; pdom != (struct domain *)NULL;
+ pdom = pdom->dom_pnext) {
+ if (strcmp(pname, pdom->dom_name) == 0)
+ return (pdom);
+ }
+
+ /* Not found. Add it to the list */
+
+ if (pdom = (struct domain *)calloc(1, sizeof (struct domain))) {
+ pdom->dom_name = strdup(pname);
+ if (pdom->dom_name == NULL) {
+ free((char *)pdom);
+ syslog(LOG_ERR,
+ "ypbind_point_to_domain: strdup failed\n");
+ return (NULL);
+ }
+ pdom->dom_pnext = known_domains;
+ known_domains = pdom;
+ pdom->dom_boundp = FALSE;
+ pdom->dom_vers = YPVERS; /* This doesn't talk to old ypserv */
+ pdom->dom_binding = NULL;
+ pdom->dom_error = YPBIND_ERR_NOSERV;
+ pdom->ping_clnt = (CLIENT *)NULL;
+ pdom->dom_report_success = -1;
+ pdom->dom_broadcaster_pid = 0;
+ pdom->broadcaster_pipe = 0;
+ pdom->bindfile = -1;
+ pdom->lastping.tv_sec = 0;
+ pdom->lastping.tv_usec = 0; /* require ping */
+ pdom->cache_fp = 0;
+ sprintf(buf, "%s/%s/cache_binding", BINDING, pdom->dom_name);
+ pdom->cache_file = strdup(buf);
+ /*
+ * We don't give an error if pdom->cache_file is not set.
+ * If we got null (out of memory), then we just won't use
+ * the cache file in cache_binding() (assuming the
+ * application gets that far.
+ */
+ }
+ else
+ syslog(LOG_ERR, "ypbind_point_to_domain: malloc failed\n");
+
+ return (pdom);
+}
+
+static void
+ypbind_ping(pdom)
+struct domain *pdom;
+{
+ struct timeval timeout;
+ int vers;
+ int isok;
+
+ if (pdom->dom_boundp == FALSE)
+ return;
+ vers = pdom->dom_vers;
+
+ if (pdom->ping_clnt == (CLIENT *) NULL) {
+ pdom->ping_clnt = __nis_clnt_create(RPC_ANYFD,
+ pdom->dom_binding->ypbind_nconf, 0,
+ pdom->dom_binding->ypbind_svcaddr, 0,
+ YPPROG, vers, 0, 0);
+ }
+
+ if (pdom->ping_clnt == (CLIENT *) NULL) {
+ perror("clnt_tli_create");
+ clnt_pcreateerror("ypbind_ping()");
+ pdom->dom_boundp = FALSE;
+ pdom->dom_error = YPBIND_ERR_NOSERV;
+ return;
+ }
+
+
+#ifdef DEBUG
+ fprintf(stderr, "ypbind: ypbind_ping()\n");
+#endif
+ timeout.tv_sec = PINGTOTTIM;
+ timeout.tv_usec = 0;
+ if (clnt_call(pdom->ping_clnt,
+ YPPROC_DOMAIN, (xdrproc_t)xdr_ypdomain_wrap_string,
+ (char *)&pdom->dom_name, xdr_int, (char *)&isok,
+ timeout) == RPC_SUCCESS) {
+ pdom->dom_boundp = isok;
+ pdom->dom_binding->ypbind_lo_vers = vers;
+ pdom->dom_binding->ypbind_hi_vers = vers;
+#ifdef DEBUG
+ fprintf(stderr,
+ "Server pinged successfully, supports versions %d thru %d\n",
+ pdom->dom_binding->ypbind_lo_vers,
+ pdom->dom_binding->ypbind_hi_vers);
+#endif
+ } else {
+ clnt_perror(pdom->ping_clnt, "ping");
+ pdom->dom_boundp = FALSE;
+ pdom->dom_error = YPBIND_ERR_NOSERV;
+ }
+ (void) gettimeofday(&(pdom->lastping), NULL);
+ if (pdom->ping_clnt)
+ clnt_destroy(pdom->ping_clnt);
+ pdom->ping_clnt = (CLIENT *)NULL;
+ if (pdom->dom_boundp)
+ cache_binding(pdom);
+}
+
+static struct ypbind_binding *
+dup_ypbind_binding(a)
+struct ypbind_binding *a;
+{
+ struct ypbind_binding *b;
+ struct netconfig *nca, *ncb;
+ struct netbuf *nxa, *nxb;
+ int i;
+
+ b = (struct ypbind_binding *)calloc(1, sizeof (*b));
+ if (b == NULL)
+ return (b);
+ b->ypbind_hi_vers = a->ypbind_hi_vers;
+ b->ypbind_lo_vers = a->ypbind_lo_vers;
+ b->ypbind_servername =
+ a->ypbind_servername ? strdup(a->ypbind_servername) : NULL;
+ ncb = (b->ypbind_nconf =
+ (struct netconfig *)calloc(1, sizeof (struct netconfig)));
+ nxb = (b->ypbind_svcaddr =
+ (struct netbuf *)calloc(1, sizeof (struct netbuf)));
+ nca = a->ypbind_nconf;
+ nxa = a->ypbind_svcaddr;
+ ncb->nc_flag = nca->nc_flag;
+ ncb->nc_protofmly =
+ nca->nc_protofmly ? strdup(nca->nc_protofmly) : NULL;
+ ncb->nc_proto =
+ nca->nc_proto ? strdup(nca->nc_proto) : NULL;
+ ncb->nc_semantics = nca->nc_semantics;
+ ncb->nc_netid =
+ nca->nc_netid ? strdup(nca->nc_netid) : NULL;
+ ncb->nc_device =
+ nca->nc_device ? strdup(nca->nc_device) : NULL;
+ ncb->nc_nlookups = nca->nc_nlookups;
+ ncb->nc_lookups = (char **)calloc(nca->nc_nlookups, sizeof (char *));
+ if (ncb->nc_lookups == NULL) {
+ if (ncb->nc_device)
+ free(ncb->nc_device);
+ if (ncb->nc_netid)
+ free(ncb->nc_netid);
+ if (ncb->nc_proto)
+ free(ncb->nc_proto);
+ if (ncb->nc_protofmly)
+ free(ncb->nc_protofmly);
+ if (nxb)
+ free(nxb);
+ if (ncb)
+ free(ncb);
+ if (b->ypbind_servername)
+ free(b->ypbind_servername);
+ if (b)
+ free(b);
+ return (NULL);
+ }
+ for (i = 0; i < nca->nc_nlookups; i++)
+ ncb->nc_lookups[i] =
+ nca->nc_lookups[i] ? strdup(nca->nc_lookups[i]) : NULL;
+ for (i = 0; i < 8; i++)
+ ncb->nc_unused[i] = nca->nc_unused[i];
+ nxb->maxlen = nxa->maxlen;
+ nxb->len = nxa->len;
+ nxb->buf = malloc(nxa->maxlen);
+ if (nxb->buf == NULL) {
+ for (i = 0; i < nca->nc_nlookups; i++)
+ if (ncb->nc_lookups[i])
+ free(ncb->nc_lookups[i]);
+ free(ncb->nc_lookups);
+ if (ncb->nc_device)
+ free(ncb->nc_device);
+ if (ncb->nc_netid)
+ free(ncb->nc_netid);
+ if (ncb->nc_proto)
+ free(ncb->nc_proto);
+ if (ncb->nc_protofmly)
+ free(ncb->nc_protofmly);
+ if (nxb)
+ free(nxb);
+ if (ncb)
+ free(ncb);
+ if (b->ypbind_servername)
+ free(b->ypbind_servername);
+ if (b)
+ free(b);
+ return (NULL);
+ }
+ memcpy(nxb->buf, nxa->buf, nxb->len);
+ return (b);
+}
+
+static void
+free_ypbind_binding(b)
+struct ypbind_binding *b;
+{
+ if (b == NULL)
+ return;
+ netdir_free((char *)b->ypbind_svcaddr, ND_ADDR);
+ free(b->ypbind_servername);
+ freenetconfigent(b->ypbind_nconf);
+ free(b);
+}
+
+/*
+ * Preloads teh default domain's domain binding. Domain binding for the
+ * local node's default domain for ypserv version 2 (YPVERS) will be
+ * set up. This may make it a little slower to start ypbind during
+ * boot time, but would make it easy on other domains that rely on
+ * this binding.
+ */
+void
+ypbind_init_default()
+{
+ char domain[256];
+ struct domain *cur_domain;
+
+ if (getdomainname(domain, 256) == 0) {
+ cur_domain = ypbind_point_to_domain(domain);
+
+ if (cur_domain == (struct domain *)NULL) {
+ abort();
+ }
+ (void) pong_servers(cur_domain);
+ }
+}
+
+bool_t
+xdr_ypbind_binding_2(xdrs, objp)
+ register XDR *xdrs;
+ ypbind_binding_2 *objp;
+{
+ if (!xdr_opaque(xdrs, (char *)&(objp->ypbind_binding_addr), 4))
+ return (FALSE);
+ if (!xdr_opaque(xdrs, (char *)&(objp->ypbind_binding_port), 2))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ypbind_resp_2(xdrs, objp)
+ register XDR *xdrs;
+ ypbind_resp_2 *objp;
+{
+ if (!xdr_ypbind_resptype(xdrs, &objp->ypbind_status))
+ return (FALSE);
+ switch (objp->ypbind_status) {
+ case YPBIND_FAIL_VAL:
+ if (!xdr_u_long(xdrs, &objp->ypbind_respbody_2.ypbind_error))
+ return (FALSE);
+ break;
+ case YPBIND_SUCC_VAL:
+ if (!xdr_ypbind_binding_2(xdrs,
+ &objp->ypbind_respbody_2.ypbind_bindinfo))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * The following is some caching code to improve the performance of
+ * yp clients. In the days of yore, a client would talk to rpcbind
+ * to get the address for ypbind, then talk to ypbind to get the
+ * address of the server. If a lot of clients are doing this at
+ * the same time, then rpcbind and ypbind get bogged down and clients
+ * start to time out.
+ *
+ * We cache two things: the current address for ypserv, and the
+ * transport addresses for talking to ypbind. These are saved in
+ * files in /var/yp. To get the address of ypserv, the client opens
+ * a file and reads the address. It does not have to talk to rpcbind
+ * or ypbind. If this file is not available, then it can read the
+ * the transport address for talking to ypbind without bothering
+ * rpcbind. If this also fails, then it uses the old method of
+ * talking to rpcbind and then ypbind.
+ *
+ * We lock the first byte of the cache files after writing to them.
+ * This indicates to the client that they contents are valid. The
+ * client should test the lock. If the lock is held, then it can
+ * use the contents. If the lock test fails, then the contents should
+ * be ignored.
+ */
+
+/*
+ * Cache new binding information for a domain in a file. If the
+ * new binding is the same as the old, then we skip it. We xdr
+ * a 'ypbind_resp', which is what would be returned by a call to
+ * the YBINDPROCP_DOMAIN service. We xdr the data because it is
+ * easier than writing the data out field by field. It would be
+ * nice if there were an xdrfd_create() that was similar to
+ * xdrstdio_create(). Instead, we do an fdopen and use xdrstdio_create().
+ */
+void
+cache_binding(pdom)
+ struct domain *pdom;
+{
+ int st;
+ int fd;
+ XDR xdrs;
+ struct ypbind_resp resp;
+
+ if (!cache_okay)
+ return;
+
+ /* if the domain doesn't have a cache file, then skip it */
+ if (pdom->cache_file == 0)
+ return;
+
+ /*
+ * If we already had a cache file for this domain, remove it. If
+ * a client just started accessing it, then it will either find
+ * it unlocked (and not use it), or continue to use it with
+ * old information. This is not a problem, the client will
+ * either fail to talk to ypserv and try to bind again, or
+ * will continue to use the old server.
+ */
+ if (pdom->cache_fp) {
+ fclose(pdom->cache_fp); /* automatically unlocks */
+ unlink(pdom->cache_file);
+ pdom->cache_fp = 0;
+ }
+
+ fd = open(pdom->cache_file, O_CREAT|O_WRONLY, 0444);
+ if (fd == -1)
+ return;
+
+ pdom->cache_fp = fdopen(fd, "w");
+ if (pdom->cache_fp == 0) {
+ close(fd);
+ return;
+ }
+
+ xdrstdio_create(&xdrs, pdom->cache_fp, XDR_ENCODE);
+ resp.ypbind_status = YPBIND_SUCC_VAL;
+ resp.ypbind_resp_u.ypbind_bindinfo = pdom->dom_binding;
+
+ if (!xdr_ypbind_resp(&xdrs, &resp)) {
+ xdr_destroy(&xdrs);
+ unlink(pdom->cache_file);
+ fclose(pdom->cache_fp);
+ pdom->cache_fp = 0;
+ return;
+ }
+ xdr_destroy(&xdrs); /* flushes xdr but leaves fp open */
+
+ /* we lock the first byte to indicate that the file is valid */
+ lseek(fd, 0L, SEEK_SET);
+ st = lockf(fd, F_LOCK, 1);
+ if (st == -1) {
+ unlink(pdom->cache_file);
+ fclose(pdom->cache_fp);
+ pdom->cache_fp = 0;
+ }
+}
+
+void
+uncache_binding(pdom)
+ struct domain *pdom;
+{
+ if (!cache_okay)
+ return;
+
+ if (pdom->cache_fp != 0) {
+ unlink(pdom->cache_file);
+ fclose(pdom->cache_fp);
+ pdom->cache_fp = 0;
+ }
+}
+
+/*
+ * Cache a transport address for talking to ypbind. We convert the
+ * transport address to a universal address and save that in a file.
+ * The file lives in the binding directory because it does not depend
+ * on the domain.
+ */
+void
+cache_transport(nconf, xprt, vers)
+ struct netconfig *nconf;
+ SVCXPRT *xprt;
+ int vers;
+{
+ char filename[300];
+ char *uaddr;
+ int fd;
+ int st;
+ int len;
+
+ if (!cache_okay)
+ return;
+
+ sprintf(filename, "%s/xprt.%s.%d",
+ BINDING, nconf->nc_netid, vers);
+
+ unlink(filename); /* remove any old version */
+
+ uaddr = taddr2uaddr(nconf, &xprt->xp_ltaddr);
+ if (uaddr == 0)
+ return;
+
+ fd = open(filename, O_CREAT|O_WRONLY, 0444); /* readable by all */
+ if (fd == -1) {
+ free(uaddr);
+ return;
+ }
+
+ len = strlen(uaddr) + 1; /* include terminating null */
+ st = write(fd, uaddr, len);
+ if (st != len) {
+ close(fd);
+ unlink(filename);
+ free(uaddr);
+ return;
+ }
+
+ free(uaddr);
+
+ /* we lock the first byte to indicate that the file is valid */
+ lseek(fd, 0L, SEEK_SET);
+ st = lockf(fd, F_LOCK, 1);
+ if (st == -1) {
+ close(fd);
+ unlink(filename);
+ }
+}
+
+/*
+ * Create a file that clients can check to see if we are running.
+ */
+void
+cache_pid()
+{
+ char filename[300];
+ char spid[15];
+ int fd;
+ int st;
+ int len;
+
+ if (!cache_okay)
+ return;
+
+ sprintf(filename, "%s/ypbind.pid", BINDING);
+
+ unlink(filename); /* remove any old version */
+
+ fd = open(filename, O_CREAT|O_WRONLY, 0444); /* readable by all */
+ if (fd == -1) {
+ return;
+ }
+
+ sprintf(spid, "%d\n", getpid());
+
+ len = strlen(spid);
+ st = write(fd, spid, len);
+ if (st != len) {
+ close(fd);
+ unlink(filename);
+ return;
+ }
+
+ /* we lock the first byte to indicate that the file is valid */
+ lseek(fd, 0L, SEEK_SET);
+ st = lockf(fd, F_LOCK, 1);
+ if (st == -1) {
+ close(fd);
+ unlink(filename);
+ }
+
+ /* we keep 'fd' open so that the lock will continue to be held */
+}
+
+/*
+ * We are called once at startup (when the known_domains list is empty)
+ * to clean up left-over files. We are also called right before
+ * exiting. In the latter case case we don't bother closing descriptors
+ * in the entries in the domain list because they will be closed
+ * automatically (and unlocked) when we exit.
+ *
+ * We ignore the cache_okay flag because it is important that we remove
+ * all cache files (left-over files can temporarily confuse clients).
+ */
+void
+clean_cache()
+{
+ struct domain *pdom;
+ DIR *dir;
+ struct dirent *dirent;
+ char filename[300];
+
+ /* close and unlink cache files for each domain */
+ for (pdom = known_domains; pdom != (struct domain *)NULL;
+ pdom = pdom->dom_pnext) {
+ if (pdom->cache_file)
+ unlink(pdom->cache_file);
+ }
+
+ sprintf(filename, "%s/ypbind.pid", BINDING);
+ unlink(filename);
+
+ dir = opendir(BINDING);
+
+ if (dir == NULL) {
+ /* Directory could not be opened. */
+ syslog(LOG_ERR, "opendir failed with [%s]", strerror(errno));
+ return;
+ }
+
+ while ((dirent = readdir(dir)) != 0) {
+ if (strncmp(dirent->d_name, "xprt.", 5) == 0) {
+ sprintf(filename, "%s/%s", BINDING, dirent->d_name);
+ unlink(filename);
+ rewinddir(dir); /* removing file may harm iteration */
+ }
+ }
+ closedir(dir);
+}
+
+/*
+ * We only want to use the cache stuff on local file systems.
+ * For remote file systems (e.g., NFS, the locking overhead is
+ * worse than the overhead of loopback RPC, so the caching
+ * wouldn't buy us anything. In addition, if the remote locking
+ * software isn't configured before we start, then we would
+ * block when we try to lock.
+ *
+ * We don't have a direct way to tell if a file system is local
+ * or remote, so we assume it is local unless it is NFS.
+ */
+int
+cache_check()
+{
+ int st;
+ struct statvfs stbuf;
+
+ st = statvfs(BINDING, &stbuf);
+ if (st == -1) {
+ syslog(LOG_ERR, "statvfs failed with [%s]", strerror(errno));
+ return (0);
+ }
+
+ /* we use strncasecmp to get NFS, NFS3, nfs, nfs3, etc. */
+ if (strncasecmp(stbuf.f_basetype, "NFS", 3) == 0)
+ return (0);
+ return (1);
+}
diff --git a/usr/src/cmd/ypcmd/yp_b_svc.c b/usr/src/cmd/ypcmd/yp_b_svc.c
new file mode 100644
index 0000000000..4cd895d3d6
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp_b_svc.c
@@ -0,0 +1,680 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <rpc/rpc.h>
+#include <memory.h>
+#include <netconfig.h>
+#include <syslog.h>
+#include <rpcsvc/yp_prot.h>
+#include "yp_b.h"
+#include <sys/resource.h>
+#include <sys/stropts.h>
+#include <unistd.h>
+#include <rpc/nettype.h>
+#include <string.h>
+#include <tiuser.h>
+
+
+#ifdef DEBUG
+#define RPC_SVC_FG
+#endif
+
+#define _RPCSVC_CLOSEDOWN 120
+#define YPBIND_ERR_ERR 1 /* Internal error */
+#define YPBIND_ERR_NOSERV 2 /* No bound server for passed domain */
+#define YPBIND_ERR_RESC 3 /* System resource allocation failure */
+#define YPBIND_ERR_NODOMAIN 4 /* Domain doesn't exist */
+
+static int _rpcpmstart; /* Started by a port monitor ? */
+static int _rpcsvcdirty; /* Still serving ? */
+int setok = YPSETNONE; /* who is allowed to ypset */
+int broadcast = 0;
+int cache_okay = 0; /* if set, then bindings are cached in files */
+
+extern int sigcld_event;
+extern void broadcast_proc_exit();
+extern int __rpc_negotiate_uid();
+extern bool_t __rpcbind_is_up();
+extern void ypbind_init_default();
+static void set_signal_handlers();
+static void clear_bindings();
+static void unregister(int);
+static int void_close(void *, int);
+void closedown();
+void ypbindprog_3();
+void ypbindprog_2();
+void msgout();
+extern void cache_transport();
+extern void clean_cache();
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ pid_t pid;
+ int pfd[2];
+ char domain[256], servers[300];
+ char **Argv = argv;
+ struct netconfig *nconf;
+ void *nc_handle;
+ int loopback_found = 0, udp_found = 0;
+ int pipe_closed = 0;
+ struct rlimit rl;
+ int connmaxrec = RPC_MAXDATASIZE;
+ uint32_t inet_tpts = 0, inet6_tpts = 0;
+ uint32_t inet_desired_tpts = 0, inet6_desired_tpts = 0;
+ bool_t exclbind = TRUE;
+
+ if (geteuid() != 0) {
+ (void) fprintf(stderr, "must be root to run %s\n", argv[0]);
+ exit(1);
+ }
+
+ argc--;
+ argv++;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-ypset") == 0) {
+ setok = YPSETALL;
+ } else if (strcmp(*argv, "-ypsetme") == 0) {
+ setok = YPSETLOCAL;
+ } else if (strcmp(*argv, "-broadcast") == 0) {
+ broadcast = TRUE;
+ } else {
+ fprintf(stderr,
+ "usage: ypbind [-broadcast] [-ypset] [-ypsetme]\n");
+ exit(1);
+ }
+ argc--,
+ argv++;
+ }
+
+ if (setok == YPSETALL) {
+ fprintf(stderr,
+ "ypbind -ypset: allowing ypset! (this is REALLY insecure)\n");
+ }
+ if (setok == YPSETLOCAL) {
+ fprintf(stderr,
+ "ypbind -ypsetme: allowing local ypset! (this is insecure)\n");
+ }
+ if (broadcast == TRUE) {
+ fprintf(stderr,
+ "ypbind -broadcast: allowing broadcast! \
+(insecure and transport dependent)\n");
+ }
+
+ if (getdomainname(domain, sizeof (domain)) == 0) {
+ sprintf(servers, "%s/%s/ypservers", BINDING, domain);
+ if (!broadcast && access(servers, R_OK) != 0) {
+ (void) fprintf(stderr,
+ "%s: no info on servers - run ypinit -c\n", Argv[0]);
+ exit(1);
+ }
+ } else {
+ (void) fprintf(stderr, "%s: domainname not set - exiting\n",
+ Argv[0]);
+ exit(1);
+ }
+
+ getrlimit(RLIMIT_NOFILE, &rl);
+ rl.rlim_cur = rl.rlim_max;
+ setrlimit(RLIMIT_NOFILE, &rl);
+
+ openlog("ypbind", LOG_PID, LOG_DAEMON);
+
+ /*
+ * If stdin looks like a TLI endpoint, we assume
+ * that we were started by a port monitor. If
+ * t_getstate fails with TBADF, this is not a
+ * TLI endpoint.
+ */
+ _rpcpmstart = (t_getstate(0) != -1 || t_errno != TBADF);
+
+ if (!__rpcbind_is_up()) {
+ msgout("terminating: rpcbind is not running");
+ exit(1);
+ }
+
+ if (_rpcpmstart) {
+ /*
+ * We were invoked by ypbind with the request on stdin.
+ *
+ * XXX - This is not the normal way ypbind is used
+ * and has never been tested.
+ */
+ char *netid;
+ struct netconfig *nconf = NULL;
+ SVCXPRT *transp;
+ int pmclose;
+ extern char *getenv();
+
+ /*
+ * Set non-blocking mode and maximum record size for
+ * connection oriented RPC transports.
+ */
+ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
+ msgout("unable to set maximum RPC record size");
+ }
+
+ clear_bindings();
+ if ((netid = getenv("NLSPROVIDER")) == NULL) {
+#ifdef DEBUG
+ msgout("cannot get transport name");
+#endif
+ } else if ((nconf = getnetconfigent(netid)) == NULL) {
+#ifdef DEBUG
+ msgout("cannot get transport info");
+#endif
+ }
+
+ pmclose = (t_getstate(0) != T_DATAXFER);
+ if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
+ msgout("cannot create server handle");
+ exit(1);
+ }
+
+ if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ if ((setok != YPSETNONE) &&
+ __rpc_negotiate_uid(transp->xp_fd)) {
+ syslog(LOG_ERR,
+ "could not negotiate with loopback tranport %s",
+ nconf->nc_netid);
+ }
+ }
+ if (nconf)
+ freenetconfigent(nconf);
+ if (!svc_reg(transp, YPBINDPROG, YPBINDVERS, ypbindprog_3, 0)) {
+ msgout("unable to register (YPBINDPROG, YPBINDVERS).");
+ exit(1);
+ }
+ if (!svc_reg(transp, YPBINDPROG, YPBINDVERS_2,
+ ypbindprog_2, 0)) {
+ msgout(
+ "unable to register (YPBINDPROG, YPBINDVERS_2).");
+ exit(1);
+ }
+ /* version 2 and version 1 are the same as far as we care */
+ if (!svc_reg(transp, YPBINDPROG, YPBINDVERS_1,
+ ypbindprog_2, 0)) {
+ msgout(
+ "unable to register (YPBINDPROG, YPBINDVERS_1).");
+ exit(1);
+ }
+ set_signal_handlers();
+ if (pmclose) {
+ (void) signal(SIGALRM, closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN);
+ }
+#ifdef INIT_DEFAULT
+ ypbind_init_default();
+#endif
+ svc_run();
+ msgout("svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+ }
+#ifndef RPC_SVC_FG
+ /*
+ * In normal operation, ypbind forks a child to do all the work
+ * so that it can run in background. But, if the parent exits
+ * too soon during system startup, clients will start trying to
+ * talk to the child ypbind before it is ready. This can cause
+ * spurious client errors.
+ *
+ * To prevent these problems, the parent process creates a pipe,
+ * which is inherited by the child, and waits for the child to
+ * close its end. This happens explicitly before the child goes
+ * into svc_run(), or as a side-effect of exiting.
+ */
+ if (pipe(pfd) == -1) {
+ perror("pipe");
+ exit(1);
+ }
+ pid = fork();
+ if (pid < 0) {
+ perror("cannot fork");
+ exit(1);
+ }
+ if (pid) {
+ /*
+ * The parent waits for the child to close its end of
+ * the pipe (to indicate that it is ready to process
+ * requests). The read blocks until the child does
+ * a close (the "domain" array is just a handy buffer).
+ */
+ close(pfd[1]);
+ read(pfd[0], domain, sizeof (domain));
+ exit(0);
+ }
+ /* close all files except pfd[1] */
+ (void) fdwalk(void_close, &pfd[1]);
+ (void) open("/dev/null", O_RDONLY);
+ (void) open("/dev/null", O_WRONLY);
+ (void) dup(1);
+ setsid();
+#endif
+ clean_cache(); /* make sure there are no left-over files */
+ cache_okay = cache_check();
+ cache_pid();
+
+ /*
+ * Set non-blocking mode and maximum record size for
+ * connection oriented RPC transports.
+ */
+ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
+ msgout("unable to set maximum RPC record size");
+ }
+
+ /*
+ * Prevent our non-priv udp and tcp ports bound w/wildcard addr
+ * from being hijacked by a bind to a more specific addr.
+ */
+ if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
+ msgout("warning: unable to set udp/tcp EXCLBIND");
+ }
+
+#ifdef INIT_DEFAULT
+ ypbind_init_default();
+#endif
+
+ nc_handle = __rpc_setconf("netpath"); /* open netconfig file */
+ if (nc_handle == NULL) {
+ syslog(LOG_ERR, "could not read /etc/netconfig, exiting..");
+ exit(1);
+ }
+
+ /*
+ * The parent waits for the child to close its end of
+ * the pipe (to indicate that it is ready to process
+ * requests). Now the non-diskless client will wait because the
+ * cache file is valid.
+ */
+ if (cache_okay) {
+ close(pfd[1]);
+ pipe_closed = 1;
+ }
+
+ clear_bindings();
+
+ while (nconf = __rpc_getconf(nc_handle)) {
+ SVCXPRT *xprt;
+
+ if (!__rpcbind_is_up()) {
+ msgout("terminating: rpcbind is not running");
+ exit(1);
+ }
+ if ((xprt = svc_tp_create(ypbindprog_3,
+ YPBINDPROG, YPBINDVERS, nconf)) == NULL) {
+ msgout("terminating: cannot create rpcbind handle");
+ exit(1);
+ }
+
+ cache_transport(nconf, xprt, YPBINDVERS);
+
+ /* support ypbind V2 and V1, but only on udp/tcp transports */
+ if (((strcmp(nconf->nc_protofmly, NC_INET) == 0) ||
+ (strcmp(nconf->nc_protofmly, NC_INET6))) &&
+ ((nconf->nc_semantics == NC_TPI_CLTS) ||
+ (nconf->nc_semantics == NC_TPI_COTS_ORD))) {
+
+ if (strcmp(nconf->nc_protofmly, NC_INET)) {
+ inet_desired_tpts |= 1 >> nconf->nc_semantics;
+ } else {
+ inet6_desired_tpts |= 1 >> nconf->nc_semantics;
+ }
+
+ (void) rpcb_unset(YPBINDPROG, YPBINDVERS_2, nconf);
+ if (!svc_reg(xprt, YPBINDPROG, YPBINDVERS_2,
+ ypbindprog_2, nconf)) {
+ syslog(LOG_INFO,
+ "unable to register (YPBINDPROG, YPBINDVERS_2) [%s]",
+ nconf->nc_netid);
+ continue;
+ }
+
+ cache_transport(nconf, xprt, YPBINDVERS_2);
+
+ /* For NC_INET, register v1 as well; error is fatal */
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+ (void) rpcb_unset(YPBINDPROG, YPBINDVERS_1,
+ nconf);
+ if (!svc_reg(xprt, YPBINDPROG, YPBINDVERS_1,
+ ypbindprog_2, nconf)) {
+ syslog(LOG_ERR,
+ "unable to register (YPBINDPROG, YPBINDVERS_1).");
+ exit(1);
+ }
+ }
+
+ cache_transport(nconf, xprt, YPBINDVERS_1);
+
+ if (nconf->nc_semantics == NC_TPI_CLTS)
+ udp_found++;
+
+ if (strcmp(nconf->nc_protofmly, NC_INET)) {
+ inet_tpts |= 1 >> nconf->nc_semantics;
+ } else {
+ inet6_tpts |= 1 >> nconf->nc_semantics;
+ }
+ }
+ if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+ loopback_found++;
+ if ((setok != YPSETNONE) &&
+ __rpc_negotiate_uid(xprt->xp_fd)) {
+ syslog(LOG_ERR,
+ "could not negotiate with loopback tranport %s",
+ nconf->nc_netid);
+ }
+ /*
+ * On a diskless client:
+ * The parent waits for the child to close its end of
+ * the pipe (to indicate that it is ready to process
+ * requests). Now the diskless client will wait
+ * only if ypbind is registered on the loopback.
+ */
+ if ((!pipe_closed) &&
+ ((nconf->nc_semantics == NC_TPI_COTS) ||
+ (nconf->nc_semantics == NC_TPI_COTS_ORD))) {
+ close(pfd[1]);
+ pipe_closed = 1;
+ }
+ }
+ }
+
+ /* Did we manage to register all IPv4 or all IPv6 transports ? */
+ if (inet_tpts != 0 && inet_tpts != inet_desired_tpts) {
+ syslog(LOG_ERR,
+ "unable to register all %s transports, exiting..",
+ NC_INET);
+ exit(1);
+ } else if (inet6_tpts != 0 && inet6_tpts != inet6_desired_tpts) {
+ syslog(LOG_ERR,
+ "unable to register all %s transports, exiting..",
+ NC_INET6);
+ exit(1);
+ }
+
+ if (!pipe_closed) {
+ close(pfd[1]);
+ pipe_closed = 1;
+ }
+ __rpc_endconf(nc_handle);
+ if (!loopback_found) {
+ syslog(LOG_ERR,
+ "could not find loopback transports, exiting..");
+ exit(1);
+ }
+ if (!udp_found) {
+ syslog(LOG_ERR,
+ "could not find inet-clts (udp) transport, exiting..");
+ exit(1);
+ }
+ set_signal_handlers();
+ svc_run();
+ syslog(LOG_ERR, "svc_run returned, exiting..");
+ exit(1);
+ /* NOTREACHED */
+}
+
+/*
+ * Callback function for fdwalk() to close all files.
+ */
+static int
+void_close(void *pfdp, int fd)
+{
+ if (fd != *(int *)pfdp)
+ (void) close(fd);
+ return (0);
+}
+
+void
+ypbindprog_3(rqstp, transp)
+ struct svc_req *rqstp;
+ register SVCXPRT *transp;
+{
+ union {
+ ypbind_domain ypbindproc_domain_3_arg;
+ ypbind_setdom ypbindproc_setdom_3_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ if (sigcld_event)
+ broadcast_proc_exit();
+
+ _rpcsvcdirty = 1;
+ switch (rqstp->rq_proc) {
+ case YPBINDPROC_NULL:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ local = (char *(*)()) ypbindproc_null_3;
+ break;
+
+ case YPBINDPROC_DOMAIN:
+ xdr_argument = xdr_ypbind_domain;
+ xdr_result = xdr_ypbind_resp;
+ local = (char *(*)()) ypbindproc_domain_3;
+ break;
+
+ case YPBINDPROC_SETDOM:
+ xdr_argument = xdr_ypbind_setdom;
+ xdr_result = xdr_void;
+ local = (char *(*)()) ypbindproc_setdom_3;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ _rpcsvcdirty = 0;
+ return;
+ }
+ (void) memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) {
+ svcerr_decode(transp);
+ _rpcsvcdirty = 0;
+ return;
+ }
+ if (rqstp->rq_proc == YPBINDPROC_SETDOM)
+ result = (*local)(&argument, rqstp, transp);
+ else
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) {
+ syslog(LOG_ERR, "unable to free arguments");
+ exit(1);
+ }
+ _rpcsvcdirty = 0;
+}
+
+void
+ypbindprog_2(rqstp, transp)
+ struct svc_req *rqstp;
+ register SVCXPRT *transp;
+{
+ union {
+ domainname_2 ypbindproc_domain_2_arg;
+ ypbind_setdom_2 ypbindproc_setdom_2_arg;
+ } argument;
+ char *result;
+ bool_t (*xdr_argument)(), (*xdr_result)();
+ char *(*local)();
+
+ if (sigcld_event)
+ broadcast_proc_exit();
+
+ _rpcsvcdirty = 1;
+ switch (rqstp->rq_proc) {
+ case YPBINDPROC_NULL:
+ xdr_argument = xdr_void;
+ xdr_result = xdr_void;
+ /* XXX - don't need two null procedures */
+ local = (char *(*)()) ypbindproc_null_3;
+ break;
+
+ case YPBINDPROC_DOMAIN:
+ xdr_argument = (bool_t (*)())xdr_ypdomain_wrap_string;
+ xdr_result = xdr_ypbind_resp_2;
+ local = (char *(*)()) ypbindproc_domain_2;
+ break;
+
+ case YPBINDPROC_SETDOM: /* not supported, fall through to error */
+ default:
+ svcerr_noproc(transp);
+ _rpcsvcdirty = 0;
+ return;
+ }
+ (void) memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) {
+ svcerr_decode(transp);
+ _rpcsvcdirty = 0;
+ return;
+ }
+ result = (*local)(&argument, rqstp);
+ if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *)&argument)) {
+ syslog(LOG_ERR, "unable to free arguments");
+ exit(1);
+ }
+ _rpcsvcdirty = 0;
+}
+
+/*
+ * We clear out any old bindings that might have been
+ * left behind. If there is already a ypbind running,
+ * it will no longer get requests. We are in control
+ * now. We ignore the error from rpcb_unset() because
+ * this is just a "best effort". If the rpcb_unset()
+ * does fail, we will get an error in svc_reg(). By
+ * using 0 for the last argument we are telling the
+ * portmapper to remove the bindings for all transports.
+ */
+static
+void
+clear_bindings()
+{
+ rpcb_unset(YPBINDPROG, YPBINDVERS, 0);
+ rpcb_unset(YPBINDPROG, YPBINDVERS_2, 0);
+ rpcb_unset(YPBINDPROG, YPBINDVERS_1, 0);
+}
+
+/*
+ * This routine is called when we are killed (by most signals).
+ * It first tries to unregister with the portmapper. Then it
+ * resets the signal handler to the default so that if we get
+ * the same signal, we will just go away. We clean up our
+ * children by doing a hold in SIGTERM and then killing the
+ * process group (-getpid()) with SIGTERM. Finally, we redeliver
+ * the signal to ourselves (the handler was reset to the default)
+ * so that we will do the normal handling (e.g., coredump).
+ * If we can't kill ourselves, we get drastic and just exit
+ * after sleeping for a couple of seconds.
+ *
+ * This code was taken from the SunOS version of ypbind.
+ */
+static
+void
+unregister(int code)
+{
+ clear_bindings();
+ clean_cache();
+ signal(code, SIG_DFL); /* to prevent recursive calls to unregister */
+ fprintf(stderr, "ypbind: goind down on signal %d\n", code);
+ sighold(SIGCHLD);
+ sighold(SIGTERM);
+ kill(-getpid(), SIGTERM); /* kill process group (i.e., children) */
+ sigrelse(SIGTERM);
+ kill(getpid(), code); /* throw signal again */
+ sleep(2);
+ exit(-1);
+}
+
+static
+void
+set_signal_handlers()
+{
+ int i;
+
+ for (i = 1; i <= SIGTERM; i++) {
+ if (i == SIGCHLD)
+ continue;
+ else if (i == SIGHUP)
+ signal(i, SIG_IGN);
+ else
+ signal(i, unregister);
+ }
+}
+
+void
+msgout(msg)
+ char *msg;
+{
+#ifdef RPC_SVC_FG
+ if (_rpcpmstart)
+ syslog(LOG_ERR, msg);
+ else
+ (void) fprintf(stderr, "%s\n", msg);
+#else
+ syslog(LOG_ERR, msg);
+#endif
+}
+
+void
+closedown()
+{
+ if (_rpcsvcdirty == 0) {
+ int i, openfd;
+ struct t_info tinfo;
+
+ if (t_getinfo(0, &tinfo) || (tinfo.servtype == T_CLTS))
+ exit(0);
+
+ for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++)
+ if (svc_pollfd[i].fd >= 0)
+ openfd++;
+
+ if (openfd <= 1)
+ exit(0);
+ }
+ (void) alarm(_RPCSVC_CLOSEDOWN);
+}
diff --git a/usr/src/cmd/ypcmd/yp_getalias.c b/usr/src/cmd/ypcmd/yp_getalias.c
new file mode 100644
index 0000000000..a383e83117
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yp_getalias.c
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include "ypsym.h"
+/* this is 14 less the space for temps pids and .pag more or less */
+
+#ifdef DEBUG
+#define YPDBDIR "/var/ypnew"
+#define ALIASLIST "/var/ypnew/aliases"
+#else
+#define YPDBDIR "/var/yp"
+#define ALIASLIST "/var/yp/aliases"
+#endif
+#define issep(c) (c == ' ' || c == '\t')
+
+#ifdef SYSVCONFIG
+#define isvar_sysv() (wasitsysv)
+
+static int wasitsysv = TRUE;
+static int first_time = TRUE;
+static listofnames *list = NULL;
+#endif
+
+void sysv_exit();
+extern listofnames *names();
+extern void exit();
+extern void free_listofnames();
+
+/*
+ * Setup alias file, check /var/yp filesystem type
+ * Note: The *never* checks for aliases under Solaris, so there is no need
+ * for this function. As of 1.1 beta 4, I will ifdef it out (cause
+ * you never know...). Should go away completely soon.
+ */
+
+#ifdef SYSVCONFIG
+void
+sysvconfig(void)
+{
+ struct statvfs statbuf;
+
+ sigset(SIGCHLD, SIG_IGN);
+ /*
+ * if neccesary free previous list, then read in aliaslist
+ */
+
+ if (!first_time)
+ free_listofnames(list);
+ else
+ first_time = FALSE;
+
+ list = names(ALIASLIST);
+
+ /*
+ * Check if YP database directory is in a system v filesystem
+ */
+
+ if (statvfs(YPDBDIR, &statbuf) != 0) {
+ fprintf(stderr, "Cannot stat %s\n", YPDBDIR);
+ exit(-1);
+ } else {
+ /* if (strcmp(statbuf.f_basetype,"s5")) (doesn't work in k13) */
+ if (statbuf.f_namemax == 14)
+ wasitsysv = TRUE;
+ else
+ wasitsysv = FALSE;
+ }
+ sigset(SIGCHLD, (void (*)())sysvconfig);
+}
+#endif
+
+/*
+ * Match key to alias
+ */
+int
+yp_getalias(key, key_alias, maxlen)
+ char *key;
+ char *key_alias;
+ int maxlen;
+{
+ listofnames *entry;
+ char *longname;
+ char *alias;
+ char name[256];
+
+#ifndef SYSVCONFIG
+ strcpy(key_alias, key);
+ return (0);
+#else
+ /* sysvconfig must be run before this routine */
+ if (key == NULL || first_time)
+ return (-1);
+
+ if (!isvar_sysv()) {
+ strcpy(key_alias, key);
+ return (0);
+ }
+
+ for (entry = list, strcpy(name, entry->name); entry;
+ entry = entry->nextname, strcpy(name, entry->name)) {
+
+ longname = strtok(name, " \t");
+ alias = strtok(NULL, " \t\n");
+ if (longname == NULL || alias == NULL) {
+ continue;
+ }
+ if (strcmp(longname, key) == 0) {
+ if ((int)strlen(alias) > (maxlen)) {
+ strncpy(key_alias, alias, (maxlen));
+ key_alias[maxlen] = '\0';
+ } else {
+ strcpy(key_alias, alias);
+ }
+ return (0);
+ }
+ }
+ /* alias not found */
+ return (-1);
+#endif
+}
+
+/*
+ * Match alias to key
+ */
+int
+yp_getkey(key_alias, key, maxlen)
+ char *key_alias;
+ char *key;
+ int maxlen;
+{
+ listofnames *entry;
+ char *longname;
+ char *alias;
+ char name[256];
+
+#ifndef SYSVCONFIG
+ strcpy(key, key_alias);
+ return (0);
+#else
+ if (key_alias == NULL || first_time) {
+ return (-1);
+ }
+
+ if (!isvar_sysv()) {
+ strcpy(key, key_alias);
+ return (0);
+ }
+
+ for (entry = list, strcpy(name, entry->name);
+ entry; entry = entry->nextname, strcpy(name, entry->name)) {
+
+ longname = strtok(name, " \t");
+ alias = strtok(NULL, " \t\n");
+ if (alias == NULL || longname == NULL) {
+ continue;
+ }
+ if ((strcmp(alias, key_alias) == 0) ||
+ (strncmp(alias, key_alias, maxlen) == 0)) {
+ strcpy(key, longname);
+ return (0);
+ }
+ }
+ /* key not found */
+ return (-1);
+#endif
+}
diff --git a/usr/src/cmd/ypcmd/ypalias.c b/usr/src/cmd/ypcmd/ypalias.c
new file mode 100644
index 0000000000..b5d8932973
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypalias.c
@@ -0,0 +1,146 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include "ypsym.h"
+
+#ifdef SYSVCONFIG
+extern void sysvconfig();
+#endif
+
+extern int yp_getalias();
+
+/*
+ * Given a domain name, return its system v alias.
+ * If there is no alias name in the alias file,
+ * create one. Rule of creation is to take the 1st
+ * NAME_MAX-4 characters and concatenate the last 4 characters.
+ * If the alias in the file is too long, trim off the end.
+ */
+
+static void
+mkdomain_alias(name, result)
+char *name, *result;
+{
+ int retval;
+ char tmpbuf[MAXNAMLEN] = {NULL};
+
+ retval = yp_getalias(name, result, NAME_MAX);
+ if (retval == -1) {
+ if ((int)strlen(name) > NAME_MAX) {
+ strncpy(result, name, NAME_MAX-4);
+ strncpy(&result[NAME_MAX-4],
+ &name[strlen(name)-4], 4);
+ result[NAME_MAX] = '\0';
+ } else
+ strcpy(result, name);
+ } else if ((retval) && (int)strlen(result) > NAME_MAX) {
+ strncpy(tmpbuf, result, NAME_MAX);
+ strcpy(result, tmpbuf);
+ }
+}
+
+/*
+ * Given a map name, return its system v alias .
+ * If there is no alias name in the alias file,
+ * create one. Rule of creation is to take the 1st
+ * MAXALIASLEN-4 characters and concatenate the last 4 characters.
+ * If the alias in the file is too long, trim off the end.
+ */
+static void
+mkmap_alias(name, result)
+char *name, *result;
+{
+ int retval;
+ char tmpbuf[MAXNAMLEN] = {NULL};
+
+ retval = yp_getalias(name, result, MAXALIASLEN);
+
+ if (retval == -1) {
+ if ((int)strlen(name) > MAXALIASLEN) {
+ (void) strncpy(result, name, MAXALIASLEN-4);
+ (void) strncpy(&result[MAXALIASLEN-4],
+ &name[strlen(name)-4], 4);
+ result[MAXALIASLEN] = '\0';
+ } else
+ (void) strcpy(result, name);
+ } else if ((retval) && (int)strlen(result) > MAXALIASLEN) {
+ (void) strncpy(tmpbuf, result, MAXALIASLEN);
+ (void) strcpy(result, tmpbuf);
+ }
+}
+
+#ifdef MAIN
+
+/*
+ * executed only for the command ypalias
+ * and not when ypbind or ypserv make use
+ * of this file.
+ */
+
+static char usage[] =
+"Usage:\n\
+ ypalias -d domainname\n\
+ ypalias mapname\n";
+
+main(argc, argv)
+char **argv;
+{
+ char result[MAXNAMLEN] = {NULL};
+
+#ifdef SYSVCONFIG
+ sysvconfig();
+#endif
+ if (argc <= 1)
+ goto err;
+ if (strcmp(argv[1], "-d") == 0)
+ if (argc == 3) mkdomain_alias(argv[2], (char *)&result);
+ else goto err;
+ else if (argc == 2)
+ mkmap_alias(argv[1], (char *)&result);
+ else
+ goto err;
+ (void) printf("%s", result);
+ return (0);
+err:
+ (void) fprintf(stderr, usage);
+ return (1);
+}
+#endif /* MAIN */
diff --git a/usr/src/cmd/ypcmd/ypcat.c b/usr/src/cmd/ypcmd/ypcat.c
new file mode 100644
index 0000000000..b515783efb
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypcat.c
@@ -0,0 +1,324 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a user command which dumps each entry in a yp data base. It gets
+ * the stuff using the normal ypclnt package; the user doesn't get to choose
+ * which server gives him the input. Usage is:
+ * ypcat [-k] [-d domain] [-t] map
+ * ypcat -x
+ * where the -k switch will dump keys followed by a single blank space
+ * before the value, and the -d switch can be used to specify a domain other
+ * than the default domain. -t switch inhibits nickname translation of map
+ * names. -x is to dump the nickname translation table from file /var/yp/
+ * nicknames.
+ *
+ */
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static int translate = TRUE;
+static int dodump = FALSE;
+static int dumpkeys = FALSE;
+static char *domain = NULL;
+static char default_domain_name[YPMAXDOMAIN];
+static char nm[YPMAXMAP+1];
+static char *map = NULL;
+static char nullstring[] = "";
+static char err_usage[] =
+"Usage:\n\
+ ypcat [-k] [-d domainname] [-t] mapname\n\
+ ypcat -x\n\
+where\n\
+ mapname may be either a mapname or a nickname for a map.\n\
+ -t inhibits map nickname translation.\n\
+ -k prints keys as well as values.\n\
+ -x dumps the map nickname translation table.\n";
+static char err_bad_args[] =
+ "ypcat: %s argument is bad.\n";
+static char err_cant_get_kname[] =
+ "ypcat: can't get %s back from system call.\n";
+static char err_null_kname[] =
+ "ypcat: the %s hasn't been set on this machine.\n";
+static char err_bad_mapname[] = "mapname";
+static char err_bad_domainname[] = "domainname";
+static char err_first_failed[] =
+ "ypcat: can't get first record from yp. Reason: %s.\n";
+static char err_next_failed[] =
+ "ypcat: can't get next record from yp. Reason: %s.\n";
+
+static void get_command_line_args();
+static int callback();
+static void one_by_one_all();
+extern void maketable();
+extern int getmapname();
+static void getdomain();
+
+/*
+ * This is the mainline for the ypcat process. It pulls whatever arguments
+ * have been passed from the command line, and uses defaults for the rest.
+ */
+
+main (argc, argv)
+ int argc;
+ char **argv;
+
+{
+ int err;
+ int fail = 0;
+ struct ypall_callback cbinfo;
+
+ get_command_line_args(argc, argv);
+
+ if (dodump) {
+ maketable(dodump);
+ exit(0);
+ }
+
+ if (!domain) {
+ getdomain();
+ }
+
+ if (translate && (strchr(map, '.') == NULL) &&
+ (getmapname(map, nm))) {
+ map = nm;
+ }
+
+ cbinfo.foreach = callback;
+ cbinfo.data = (char *) &fail;
+ err = __yp_all_rsvdport(domain, map, &cbinfo);
+
+ if (err == YPERR_VERS) {
+ one_by_one_all(domain, map);
+ } else if (err) {
+ fail = TRUE;
+ fprintf (stderr, "%s\n", yperr_string(err));
+ }
+
+ exit(fail);
+}
+
+/*
+ * This does the command line argument processing.
+ */
+static void
+get_command_line_args(argc, argv)
+ int argc;
+ char **argv;
+
+{
+
+ argv++;
+
+ while (--argc > 0 && (*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+
+ case 't':
+ translate = FALSE;
+ break;
+
+ case 'k':
+ dumpkeys = TRUE;
+ break;
+
+ case 'x':
+ dodump = TRUE;
+ break;
+
+ case 'd':
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+
+ if ((int)strlen(domain) > YPMAXDOMAIN) {
+ (void) fprintf(stderr, err_bad_args,
+ err_bad_domainname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ break;
+
+ default:
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+ argv++;
+ }
+
+ if (!dodump) {
+ map = *argv;
+ if (argc < 1) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+ if ((int) strlen(map) > YPMAXMAP) {
+ (void) fprintf(stderr, err_bad_args, err_bad_mapname);
+ exit(1);
+ }
+ }
+}
+
+/*
+ * This dumps out the value, optionally the key, and perhaps an error message.
+ */
+static int
+callback(status, key, kl, val, vl, fail)
+ int status;
+ char *key;
+ int kl;
+ char *val;
+ int vl;
+ int *fail;
+{
+ int e;
+
+ if (status == YP_TRUE) {
+
+ if (dumpkeys)
+ (void) printf("%.*s ", kl, key);
+
+ (void) printf("%.*s\n", vl, val);
+ return (FALSE);
+ } else {
+
+ e = ypprot_err(status);
+
+ if (e != YPERR_NOMORE) {
+ (void) fprintf(stderr, "%s\n", yperr_string(e));
+ *fail = TRUE;
+ }
+
+ return (TRUE);
+ }
+}
+
+/*
+ * This cats the map out by using the old one-by-one enumeration interface.
+ * As such, it is prey to the old-style problems of rebinding to different
+ * servers during the enumeration.
+ */
+static void
+one_by_one_all(domain, map)
+char *domain;
+char *map;
+{
+ char *key;
+ int keylen;
+ char *outkey;
+ int outkeylen;
+ char *val;
+ int vallen;
+ int err;
+
+ key = nullstring;
+ keylen = 0;
+ val = nullstring;
+ vallen = 0;
+
+ if (err = yp_first(domain, map, &outkey, &outkeylen, &val, &vallen)) {
+
+ if (err == YPERR_NOMORE) {
+ exit(0);
+ } else {
+ (void) fprintf(stderr, err_first_failed,
+ yperr_string(err));
+ exit(1);
+ }
+ }
+
+ for (;;) {
+
+ if (dumpkeys) {
+ (void) printf("%.*s ", outkeylen, outkey);
+ }
+
+ (void) printf("%.*s\n", vallen, val);
+ free(val);
+ key = outkey;
+ keylen = outkeylen;
+
+ if (err = yp_next(domain, map, key, keylen, &outkey, &outkeylen,
+ &val, &vallen)) {
+
+ if (err == YPERR_NOMORE) {
+ break;
+ } else {
+ (void) fprintf(stderr, err_next_failed,
+ yperr_string(err));
+ exit(1);
+ }
+ }
+
+ free(key);
+ }
+}
+
+/*
+ * This gets the local default domainname, and makes sure that it's set
+ * to something reasonable. domain is set here.
+ */
+static void
+getdomain()
+{
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ (void) fprintf(stderr, err_cant_get_kname, err_bad_domainname);
+ exit(1);
+ }
+
+ if ((int) strlen(domain) == 0) {
+ (void) fprintf(stderr, err_null_kname, err_bad_domainname);
+ exit(1);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/ypdefs.h b/usr/src/cmd/ypcmd/ypdefs.h
new file mode 100644
index 0000000000..abd9d76386
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypdefs.h
@@ -0,0 +1,104 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef __YPDEFS_H
+#define __YPDEFS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ypdefs.h
+ * Special, internal keys to NIS maps. These keys are used
+ * by various maintain functions of the NIS and invisible
+ * to yp clients. By definition, any key beginning with yp_prefix is
+ * an internal key.
+ */
+
+#define USE_YP_PREFIX \
+ static char yp_prefix[] = "YP_"; \
+ static int yp_prefix_sz = sizeof (yp_prefix) - 1;
+
+#define USE_YP_MASTER_NAME \
+ static char yp_master_name[] = "YP_MASTER_NAME"; \
+ static int yp_master_name_sz = sizeof (yp_master_name) - 1;
+#define MAX_MASTER_NAME 256
+
+#define USE_YP_LAST_MODIFIED \
+ static char yp_last_modified[] = "YP_LAST_MODIFIED"; \
+ static int yp_last_modified_sz = sizeof (yp_last_modified) - 1;
+
+#define MAX_ASCII_ORDER_NUMBER_LENGTH 10
+
+#define USE_YP_INPUT_FILE \
+ static char yp_input_file[] = "YP_INPUT_FILE"; \
+ static int yp_input_file_sz = sizeof (yp_input_file) - 1;
+
+#define USE_YP_OUTPUT_NAME \
+ static char yp_output_file[] = "YP_OUTPUT_NAME"; \
+ static int yp_output_file_sz = sizeof (yp_output_file) - 1;
+
+#define USE_YP_DOMAIN_NAME \
+ static char yp_domain_name[] = "YP_DOMAIN_NAME"; \
+ static int yp_domain_name_sz = sizeof (yp_domain_name) - 1;
+
+#define USE_YP_SECURE \
+ static char yp_secure[] = "YP_SECURE"; \
+ static int yp_secure_sz = sizeof (yp_secure) - 1;
+
+#define USE_YP_INTERDOMAIN \
+ static char yp_interdomain[] = "YP_INTERDOMAIN"; \
+ static int yp_interdomain_sz = sizeof (yp_interdomain) - 1;
+
+/*
+ * Definitions of where the NIS servers keep their databases.
+ * These are really only implementation details.
+ */
+
+#define USE_YPDBPATH \
+ static char ypdbpath[] = "/var/yp"; \
+ static int ypdbpath_sz = sizeof (ypdbpath) - 1;
+
+#define USE_DBM \
+ static char dbm_dir[] = ".dir"; \
+ static char dbm_pag[] = ".pag";
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __YPDEFS_H */
diff --git a/usr/src/cmd/ypcmd/ypinit.sh b/usr/src/cmd/ypcmd/ypinit.sh
new file mode 100644
index 0000000000..f004e9501d
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypinit.sh
@@ -0,0 +1,515 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+# Portions of this source code were derived from Berkeley 4.3 BSD
+# under license from the Regents of the University of California.
+
+#ident "%Z%%M% %I% %E% SMI"
+
+# set -xv
+YPXFR=/usr/lib/netsvc/yp/ypxfr
+MAKEPATH=/usr/ccs/bin
+maps="publickey publickey.byname"
+yproot_dir=/var/yp
+yproot_exe=/usr/sbin/yp
+hf=/var/run/ypservers.$$
+XFR=${YPXFR}
+
+hosts_file=/etc/hosts
+hosts6_file=/etc/inet/ipnodes
+clientp=F
+masterp=F
+slavep=F
+host=""
+def_dom=""
+master=""
+got_host_list=F
+first_time=T
+exit_on_error=F
+errors_in_setup=F
+
+enable_next_boot () {
+ /usr/sbin/svcadm disable -t $1
+ [ $? = 0 ] || echo "ypinit: unable to temporarily disable $1"
+ /usr/sbin/svccfg -s $1 \
+ setprop general/enabled = true
+ [ $? = 0 ] || echo "ypinit: unable to enable $1 for next boot"
+}
+
+enable_this_boot () {
+ /usr/sbin/svcadm enable $1
+ [ $? = 0 ] || echo "ypinit: unable to enable $1"
+}
+
+PATH=/bin:/usr/bin:/usr/etc:/usr/sbin:$yproot_exe:$MAKEPATH:$PATH
+export PATH
+
+# To do cleanup
+trap '/usr/bin/rm -f $hf' 0 1 2 3 15
+
+case $# in
+1) case $1 in
+ -c) clientp=T;;
+ -m) masterp=T;;
+ *) echo 'usage:'
+ echo ' ypinit -c'
+ echo ' ypinit -m'
+ echo ' ypinit -s master_server'
+ echo ""
+ echo "\
+where -c is used to set up a yp client, -m is used to build a master "
+ echo "\
+yp server data base, and -s is used for a slave data base."
+ echo "\
+master_server must be an existing reachable yp server."
+ exit 1;;
+ esac;;
+
+2) case $1 in
+ -s) slavep=T; master=$2;
+ if ( grep $master $hosts_file $hosts6_file > /dev/null )
+ then
+ echo ""
+ else
+ echo "server not found in $hosts_file or $hosts6_file"
+ exit 1
+ fi;;
+
+ *) echo 'usage:'
+ echo ' ypinit -c'
+ echo ' ypinit -m'
+ echo ' ypinit -s master_server'
+ echo ""
+ echo "\
+where -c is used to set up a yp client, -m is used to build a master "
+ echo "\
+yp server data base, and -s is used for a slave data base."
+ echo "\
+master_server must be an existing reachable yp server."
+ exit 1;;
+ esac;;
+3) case $1 in
+ -c) clientp=T;;
+ *) echo 'usage:'
+ echo ' ypinit -c'
+ echo ' ypinit -m'
+ echo ' ypinit -s master_server'
+ echo ""
+ echo "\
+where -c is used to set up a yp client, -m is used to build a master "
+ echo "\
+yp server data base, and -s is used for a slave data base."
+ echo "\
+master_server must be an existing reachable yp server."
+ exit 1;;
+ esac;;
+
+*) echo 'usage:'
+ echo ' ypinit -c'
+ echo ' ypinit -m'
+ echo ' ypinit -s master_server'
+ echo ""
+ echo "\
+where -c is used to set up a yp client, -m is used to build a master "
+ echo "\
+yp server data base, and -s is used for a slave data base."
+ echo "\
+master_server must be an existing reachable yp server."
+ exit 1;;
+esac
+
+if [ $? -ne 0 ]
+then
+ echo "\
+You have to be the superuser to run this. Please log in as root."
+ exit 1
+fi
+
+host=`uname -n`
+
+if [ $? -ne 0 ]
+then
+ echo "Can't get local host's name. Please check your path."
+ exit 1
+fi
+
+if [ -z "$host" ]
+then
+ echo "The local host's name hasn't been set. Please set it."
+ exit 1
+fi
+
+def_dom=`domainname`
+
+if [ $? -ne 0 ]
+then
+ echo "Can't get local host's domain name. Please check your path."
+ exit 1
+fi
+
+if [ -z "$def_dom" ]
+then
+ echo "The local host's domain name hasn't been set. Please set it."
+ exit 1
+fi
+
+domainname $def_dom
+real_def_dom=$def_dom
+#def_dom=`ypalias -d $def_dom`
+ypservers_map=`ypalias ypservers`
+domain_dir="$yproot_dir""/""$def_dom"
+binding_dir="$yproot_dir""/binding/""$def_dom"
+binding_file="$yproot_dir""/binding/""$def_dom""/ypservers"
+
+if [ ! -d $yproot_dir -o -f $yproot_dir ]
+then
+ echo "\
+The directory $yproot_dir doesn't exist. Restore it from the distribution."
+ exit 1
+fi
+
+# add domainname and ypservers aliases to aliases file
+echo ypservers $ypservers_map >> $yproot_dir/aliases
+echo $real_def_dom $def_dom >> $yproot_dir/aliases
+sort $yproot_dir/aliases | uniq > /var/run/.ypaliases; mv /var/run/.ypaliases $yproot_dir/aliases
+
+if [ ! -d "$yproot_dir"/binding ]
+then
+ mkdir "$yproot_dir"/binding
+fi
+
+if [ ! -d $binding_dir ]
+then
+ mkdir "$binding_dir"
+fi
+
+if [ $slavep = F ]
+then
+ while [ $got_host_list = F ]; do
+ touch $hf # make sure file exists
+ echo ""
+ echo "\
+In order for NIS to operate sucessfully, we have to construct a list of the "
+ echo "\
+NIS servers. Please continue to add the names for YP servers in order of"
+ echo "\
+preference, one per line. When you are done with the list, type a <control D>"
+ echo "\
+or a return on a line by itself."
+ if [ $masterp = T ]
+ then
+ echo $host > $hf
+ echo "\tnext host to add: $host"
+ elif [ -f $binding_file ]
+ then
+ if [ $first_time = T ]
+ then
+ for h in `cat $binding_file`
+ do
+ echo $h >> $hf
+ echo "\tnext host to add: $h"
+ done
+ fi
+ fi
+
+ echo "\tnext host to add: \c"
+
+ while read h ; test -n "$h"
+ do
+ if ( grep $h $hosts_file $hosts6_file > /dev/null )
+ then
+ echo $h >> $hf
+ echo "\tnext host to add: \c"
+ else
+ echo "host $h not found in $hosts_file or $hosts6_file. Not added to the list"
+ echo ""
+ echo "Do you wish to abort [y/n: y] \c"
+ read cont_ok
+
+ case $cont_ok in
+ n*) echo "\tnext host to add: \c";;
+ N*) echo "\tnext host to add: \c";;
+ *) exit 1;;
+ esac
+ fi
+
+ done
+
+ echo ""
+ if [ -s $hf ]
+ then
+ echo "The current list of yp servers looks like this:"
+ echo ""
+ cat $hf
+ echo ""
+ echo "Is this correct? [y/n: y] \c"
+ else
+ echo "You have not added any server information."
+ echo ""
+ echo "Do you still wish to exit? [y/n: y] \c"
+ fi
+
+ read hlist_ok
+
+ case $hlist_ok in
+ n*) got_host_list=F
+ first_time=F
+ rm $hf
+ echo "Let's try the whole thing again...";;
+ N*) got_host_list=F
+ first_time=F
+ rm $hf
+ echo "Let's try the whole thing again...";;
+ *) got_host_list=T;;
+ esac
+ done
+
+ if [ -s $hf ]
+ then
+ cp $hf $binding_file
+ fi
+fi
+
+#
+# Start client service on next boot, unless we're establishing a slave
+# server, in which case the binding is needed now (or should be
+# preserved).
+#
+if [ $slavep = T ]
+then
+ enable_this_boot network/nis/client:default
+else
+ enable_next_boot network/nis/client:default
+fi
+
+#
+# As a client, our configuration is correct once a binding file is
+# established, and so we can exit (making sure we're no longer a server,
+# of course).
+#
+if [ $clientp = T ]
+then
+ rm $hf
+ /usr/sbin/svcadm disable network/nis/server:default
+ /usr/sbin/svcadm disable network/nis/xfr:default
+ /usr/sbin/svcadm disable network/nis/passwd:default
+ /usr/sbin/svcadm disable network/nis/update:default
+ exit 0
+fi
+
+if [ $slavep = T ]
+then
+ if [ $host = $master ]
+ then
+ echo "\
+The host specified should be a running master yp server, not this machine."
+ exit 1
+ fi
+
+ maps=`ypwhich -m | egrep $master$| awk '{ printf("%s ",$1) }' -`
+ if [ -z "$maps" ]
+ then
+ echo "Can't enumerate maps from $master. Please check that it is running."
+ exit 1
+ fi
+fi
+
+echo ""
+
+echo "Installing the YP database will require that you answer a few questions."
+echo "Questions will all be asked at the beginning of the procedure."
+echo ""
+echo "Do you want this procedure to quit on non-fatal errors? [y/n: n] \c"
+read doexit
+
+case $doexit in
+y*) exit_on_error=T;;
+Y*) exit_on_error=T;;
+*) echo "\
+OK, please remember to go back and redo manually whatever fails. If you"
+ echo "\
+don't, some part of the system (perhaps the yp itself) won't work.";;
+esac
+
+echo "The yp domain directory is $yproot_dir""/""$def_dom"
+
+for dir in $yproot_dir/$def_dom
+do
+
+ if [ -d $dir ]; then
+ echo "Can we destroy the existing $dir and its contents? [y/n: n] \c"
+ read kill_old_dir
+
+ case $kill_old_dir in
+ y*) rm -r -f $dir
+
+ if [ $? -ne 0 ]
+ then
+ echo "Can't clean up old directory $dir. Fatal error."
+ exit 1
+ fi;;
+
+ Y*) rm -r -f $dir
+
+ if [ $? -ne 0 ]
+ then
+ echo "Can't clean up old directory $dir. Fatal error."
+ exit 1
+ fi;;
+
+ *) echo "OK, please clean it up by hand and start again. Bye"
+ exit 0;;
+ esac
+ fi
+
+ mkdir $dir
+
+ if [ $? -ne 0 ]
+ then
+ echo "Can't make new directory $dir. Fatal error."
+ exit 1
+ fi
+
+done
+
+if [ $slavep = T ]
+then
+ echo "\
+There will be no further questions. The remainder of the procedure should take"
+ echo "a few minutes, to copy the data bases from $master."
+
+ for dom in $real_def_dom
+ do
+ for map in $maps
+ do
+ echo "Transferring $map..."
+ $XFR -h $master -c -d $dom $map
+
+ if [ $? -ne 0 ]
+ then
+ errors_in_setup=T
+
+ if [ $exit_on_error = T ]
+ then
+ exit 1
+ fi
+ fi
+ done
+ done
+
+ echo ""
+ echo "${host}'s nis data base has been set up\n"
+
+ if [ $errors_in_setup = T ]
+ then
+ echo " with errors. Please remember"
+ echo "to figure out what went wrong, and fix it."
+ else
+ echo " without any errors."
+ fi
+
+ # enable slave services
+ enable_this_boot network/nis/server:default
+
+ enable_this_boot network/nis/client:default
+
+ exit 0
+else
+
+ rm -f $yproot_dir/*.time
+
+ echo "\
+There will be no further questions. The remainder of the procedure should take"
+ echo "5 to 10 minutes."
+
+ echo "Building $yproot_dir/$def_dom/ypservers..."
+ makedbm $hf $yproot_dir/$def_dom/$ypservers_map
+
+ if [ $? -ne 0 ]
+ then
+ echo "\
+Couldn't build yp data base $yproot_dir/$def_dom/$ypservers_map."
+ errors_in_setup=T
+
+ if [ $exit_on_error = T ]
+ then
+ exit 1
+ fi
+ fi
+
+ rm $hf
+
+ in_pwd=`pwd`
+ cd $yproot_dir
+ echo "Running \c"
+ echo $yproot_dir "\c"
+ echo "/Makefile..."
+ make NOPUSH=1
+
+ if [ $? -ne 0 ]
+ then
+ echo "\
+Error running Makefile."
+ errors_in_setup=T
+
+ if [ $exit_on_error = T ]
+ then
+ exit 1
+ fi
+ fi
+
+ cd $in_pwd
+ echo ""
+ echo "\
+$host has been set up as a yp master server\c"
+
+ if [ $errors_in_setup = T ]
+ then
+ echo " with errors. Please remember"
+ echo "to figure out what went wrong, and fix it."
+ else
+ echo " without any errors."
+ fi
+
+ echo ""
+ echo "\
+If there are running slave yp servers, run yppush now for any data bases"
+ echo "\
+which have been changed. If there are no running slaves, run ypinit on"
+ echo "\
+those hosts which are to be slave servers."
+
+ # enable master services
+ enable_this_boot network/nis/server:default
+ enable_this_boot network/nis/xfr:default
+ enable_this_boot network/nis/passwd:default
+ enable_this_boot network/nis/update:default
+
+ enable_this_boot network/nis/client:default
+fi
diff --git a/usr/src/cmd/ypcmd/ypmatch.c b/usr/src/cmd/ypcmd/ypmatch.c
new file mode 100644
index 0000000000..003f5373f5
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypmatch.c
@@ -0,0 +1,299 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a user command which looks up the value of a key in a map
+ *
+ * Usage is:
+ * ypmatch [-d domain] [-t] [-k] key [key ...] mname
+ * ypmatch -x
+ *
+ * where: the -d switch can be used to specify a domain other than the
+ * default domain. mname may be either a mapname, or a nickname which
+ * will be translated into a mapname according this translation. The
+ * -k switch prints keys as well as values. The -x switch may be used
+ * to dump the translation table.
+ */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static void get_command_line_args();
+static void getdomain();
+static bool match_list();
+static bool match_one();
+static void print_one();
+extern void maketable();
+extern int getmapname();
+extern int yp_match_rsvdport ();
+
+static int translate = TRUE;
+static int dodump = FALSE;
+static int printkeys = FALSE;
+static char *domain = NULL;
+static char default_domain_name[YPMAXDOMAIN];
+static char *map = NULL;
+static char nm[YPMAXMAP+1];
+static char **keys = NULL;
+static int nkeys;
+static char err_usage[] =
+"Usage:\n\
+ ypmatch [-d domain] [-t] [-k] key [key ...] mname\n\
+ ypmatch -x\n\
+where\n\
+ mname may be either a mapname or a nickname for a map\n\
+ -t inhibits map nickname translation\n\
+ -k prints keys as well as values.\n\
+ -x dumps the map nickname translation table.\n";
+static char err_bad_args[] =
+ "ypmatch: %s argument is bad.\n";
+static char err_cant_get_kname[] =
+ "ypmatch: can't get %s back from system call.\n";
+static char err_null_kname[] =
+ "ypmatch: the %s hasn't been set on this machine.\n";
+static char err_bad_mapname[] = "mapname";
+static char err_bad_domainname[] = "domainname";
+
+/*
+ * This is the main line for the ypmatch process.
+ */
+main(argc, argv)
+ char **argv;
+{
+ get_command_line_args(argc, argv);
+
+ if (dodump) {
+ maketable(dodump);
+ exit(0);
+ }
+
+ if (!domain) {
+ getdomain();
+ }
+
+ if (translate && (strchr(map, '.') == NULL) &&
+ (getmapname(map, nm))) {
+ map = nm;
+ }
+
+ if (!match_list())
+ return (1);
+ return (0);
+}
+
+/*
+ * This does the command line argument processing.
+ */
+static void
+get_command_line_args(argc, argv)
+ int argc;
+ char **argv;
+
+{
+
+ if (argc < 2) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+ argv++;
+
+ while (--argc > 0 && (*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+
+ case 't':
+ translate = FALSE;
+ break;
+
+ case 'k':
+ printkeys = TRUE;
+ break;
+
+ case 'x':
+ dodump = TRUE;
+ break;
+
+ case 'd':
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+
+ if ((int) strlen(domain) > YPMAXDOMAIN) {
+ (void) fprintf(stderr, err_bad_args,
+ err_bad_domainname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ break;
+
+ default:
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ argv++;
+ }
+
+ if (!dodump) {
+ if (argc < 2) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ keys = argv;
+ nkeys = argc -1;
+ map = argv[argc -1];
+
+ if ((int) strlen(map) > YPMAXMAP) {
+ (void) fprintf(stderr, err_bad_args, err_bad_mapname);
+ exit(1);
+ }
+ }
+}
+
+/*
+ * This gets the local default domainname, and makes sure that it's set
+ * to something reasonable. domain is set here.
+ */
+static void
+getdomain()
+{
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ (void) fprintf(stderr, err_cant_get_kname, err_bad_domainname);
+ exit(1);
+ }
+
+ if ((int) strlen(domain) == 0) {
+ (void) fprintf(stderr, err_null_kname, err_bad_domainname);
+ exit(1);
+ }
+}
+
+/*
+ * This traverses the list of argument keys.
+ */
+static bool
+match_list()
+{
+ bool error;
+ bool errors = FALSE;
+ char *val;
+ int len;
+ int n = 0;
+
+ while (n < nkeys) {
+ error = match_one(keys[n], &val, &len);
+
+ if (!error) {
+ print_one(keys[n], val, len);
+ free(val);
+ } else {
+ errors = TRUE;
+ }
+
+ n++;
+ }
+
+ return (!errors);
+}
+
+/*
+ * This fires off a "match" request to any old yp server, using the vanilla
+ * yp client interface. To cover the case in which trailing NULLs are included
+ * in the keys, this retrys the match request including the NULL if the key
+ * isn't in the map.
+ */
+static bool
+match_one(key, val, len)
+ char *key;
+ char **val;
+ int *len;
+{
+ int err;
+ bool error = FALSE;
+
+ *val = NULL;
+ *len = 0;
+ err = yp_match_rsvdport(domain, map, key, (int) strlen(key), val, len);
+
+
+ if (err == YPERR_KEY) {
+ err = yp_match_rsvdport(domain, map, key, ((int) strlen(key) + 1),
+ val, len);
+ }
+
+ if (err) {
+ (void) fprintf(stderr,
+ "Can't match key %s in map %s. Reason: %s.\n", key, map,
+ yperr_string(err));
+ error = TRUE;
+ }
+
+ return (error);
+}
+
+/*
+ * This prints the value, (and optionally, the key) after first checking that
+ * the last char in the value isn't a NULL. If the last char is a NULL, the
+ * \n\0 sequence which the yp client layer has given to us is shuffled back
+ * one byte.
+ */
+static void
+print_one(key, val, len)
+ char *key;
+ char *val;
+ int len;
+{
+ if (printkeys) {
+ (void) printf("%s: ", key);
+ }
+
+ (void) printf("%.*s\n", len, val);
+}
diff --git a/usr/src/cmd/ypcmd/yppasswd/Makefile b/usr/src/cmd/ypcmd/yppasswd/Makefile
new file mode 100644
index 0000000000..0acfff4fc6
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/Makefile
@@ -0,0 +1,119 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+NETYPPROG = rpc.yppasswdd # pwconv passmgmt
+DFLTSRC = yppasswdd.dfl
+PROG = $(NETYPPROG)
+
+MANIFEST = passwd.xml
+
+include ../../Makefile.cmd
+
+ROOTMANIFESTDIR = $(ROOTSVCNETWORKNIS)
+
+#installed directories
+RPCSVC= $(ROOT)/usr/include/rpcsvc
+NETSVC = $(ROOTLIB)/netsvc
+NETYP = $(NETSVC)/yp
+DFLTDIR = $(ROOTETC)/default
+ROOTDIRS = $(NETSVC) $(NETYP) $(ROOTETC) $(DFLTDIR)
+
+# include library definitions
+#LDLIBS += -lrpcsvc -lnsl -lcrypt -lintl -lgen
+LDLIBS += -lnsl -lcmd -lc -lnisdb
+
+# Pick up includes from library
+CPPFLAGS += -I$(SRC)/lib/libnisdb/yptol
+
+# This file is now in the $(SRC)/head/rpcsvc directory.
+#HDRFILE= yppasswd.h
+#IHDRFILE= $(HDRFILE:%=$(RPCSVC)/%)
+
+INETYPPROG= $(NETYPPROG:%=$(NETYP)/%)
+ETCDFLTFILE= $(NETYPPROG:rpc.%=$(DFLTDIR)/%)
+
+COMMONOBJ = yppasswdxdr.o yplckpwdf.o
+RPCYPPASSWDDOBJ = yppasswdd.o changepasswd.o
+#YPPWCONVOBJ = pwconv.o
+#YPPASSMGMTOBJ = passmgmt.o
+
+#
+# Objects shared between all the major components
+#
+SHAREDOBJ= ../shared/utils.o ../shared/lockmap.o ../shared/ancil.o
+
+OBJS = $(RPCYPPASSWDDOBJ) \
+ $(COMMONOBJ)
+ # $(YPPWCONVOBJ) $(YPPASSMGMTOBJ)
+
+SRCS = $(OBJS:%.o=%.c)
+
+#conditional assignments
+$(INETSVC) := GROUP=bin
+$(INETSVC) := FILEMODE=555
+
+$(ETCDFLTFILE) := GROUP=sys
+$(ETCDFLTFILE) := FILEMODE=0444
+
+$(ROOTMANIFEST) := FILEMODE = 0444
+
+#install rules
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+rpc.yppasswdd: $(RPCYPPASSWDDOBJ) $(COMMONOBJ)
+ $(LINK.cc) -o $@ $(RPCYPPASSWDDOBJ) \
+ $(SHAREDOBJ) $(COMMONOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTDIRS) $(IBINPROG) $(INETYPPROG) $(ETCDFLTFILE) \
+ $(ROOTMANIFEST)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+$(NETYP)/%: %
+ $(INS.file)
+
+$(DFLTDIR)/% : %.dfl
+ $(INS.rename)
+
+clean:
+ $(RM) $(OBJS)
+
+lint: lint_SRCS
+
+check: $(CHKMANIFEST)
+
+cstyle:
+ ${CSTYLE} ${SRCS}
+
+# include library targets
+include ../../Makefile.targ
diff --git a/usr/src/cmd/ypcmd/yppasswd/changepasswd.c b/usr/src/cmd/ypcmd/yppasswd/changepasswd.c
new file mode 100644
index 0000000000..8adf205c55
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/changepasswd.c
@@ -0,0 +1,766 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright 1994-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Beware those who enter here.
+ * The logic may appear hairy, but it's been ARCed.
+ * See /shared/sac/PSARC/1995/122/mail
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <signal.h>
+#include <crypt.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yppasswd.h>
+#include <utmpx.h>
+#include <nss_dbdefs.h>
+
+#define STRSIZE 100
+#define FINGERSIZE (4 * STRSIZE - 4)
+#define SHELLSIZE (STRSIZE - 2)
+#define UTUSERLEN (sizeof (((struct utmpx *)0)->ut_user))
+
+/* Prototypes */
+extern bool_t validloginshell(char *sh, char *arg, int);
+extern int validstr(char *str, size_t size);
+extern int yplckpwdf();
+extern int ypulckpwdf();
+
+void
+changepasswd(SVCXPRT *transp)
+{
+ /*
+ * Put these numeric constants into const variables so
+ * a) they're visible in a debugger
+ * b) the compiler can play it's cool games with em
+ */
+ static const int cryptpwsize = CRYPT_MAXCIPHERTEXTLEN;
+ static const int fingersize = FINGERSIZE;
+ static const int shellsize = SHELLSIZE;
+
+ struct yppasswd yppwd;
+ struct passwd newpw, opwd;
+ struct spwd ospwd;
+ struct sigaction sa, osa1, osa2, osa3;
+ struct stat pwstat, spstat, adjstat;
+
+ char newpasswdfile[FILENAME_MAX];
+ char newshadowfile[FILENAME_MAX];
+ char newadjunctfile[FILENAME_MAX];
+ char tmppasswdfile[FILENAME_MAX];
+ char tmpshadowfile[FILENAME_MAX];
+ char tmpadjunctfile[FILENAME_MAX];
+ char pwbuf[NSS_LINELEN_PASSWD], spbuf[NSS_LINELEN_SHADOW];
+ char adjbuf[BUFSIZ+1], adjbuf_new[BUFSIZ+1], cmdbuf[BUFSIZ];
+ char adj_encrypt[CRYPT_MAXCIPHERTEXTLEN + 1];
+ /*
+ * The adj_crypt_* pointers are used to point into adjbuf
+ * NOT adj_encrypt
+ */
+ char *adj_crypt_begin, *adj_crypt_end;
+ char name[UTUSERLEN + sizeof (":")];
+ char *p;
+
+ FILE *opwfp = NULL, *ospfp = NULL, *oadjfp = NULL,
+ *npwfp = NULL, *nspfp = NULL, *nadjfp = NULL;
+ int npwfd = -1, nspfd = -1, nadjfd = -1;
+
+ int i, ans, chsh, chpw, chgecos, namelen;
+ int gotadjunct = 0, gotshadow = 0, gotpasswd = 0;
+ int doneflag = 0, root_on_master = 0;
+ pid_t retval;
+
+ time_t now;
+
+ long pwpos = 0, sppos = 0;
+
+ /* Globals :-( */
+ extern int single, nogecos, noshell, nopw, mflag, Mstart, Argc;
+ extern char **Argv;
+ extern char passwd_file[], shadow_file[], adjunct_file[];
+ extern int useadjunct;
+ extern int useshadow;
+
+ /* Clean out yppwd */
+ memset(&yppwd, 0, sizeof (struct yppasswd));
+
+ /* Get the RPC args */
+ if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ /* Perform basic validation */
+ if (/* (!validstr(yppwd.oldpass, PWSIZE)) || */ /* see PR:nis/38 */
+ (!validstr(yppwd.newpw.pw_passwd, cryptpwsize)) ||
+ (!validstr(yppwd.newpw.pw_name, UTUSERLEN)) ||
+ (!validstr(yppwd.newpw.pw_gecos, fingersize)) ||
+ (!validstr(yppwd.newpw.pw_shell, shellsize))) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ /*
+ * Special case: root on the master server can change other users'
+ * passwords without first entering the old password. We need to
+ * ensure that this is indeed root on the master server. (bug 1253949)
+ */
+ if (strcmp(transp->xp_netid, "ticlts") == 0) {
+ svc_local_cred_t cred;
+ if (!svc_get_local_cred(transp, &cred)) {
+ syslog(LOG_ERR, "yppasswdd: Couldn't get "
+ "local user credentials.\n");
+ } else if (cred.ruid == 0)
+ root_on_master = 1;
+ }
+
+ newpw = yppwd.newpw;
+ strcpy(name, newpw.pw_name);
+ strcat(name, ":");
+ namelen = strlen(name);
+ ans = 2;
+ chsh = chpw = chgecos = 0;
+
+ /* Get all the filenames straight */
+ strcpy(newpasswdfile, passwd_file);
+ strcat(newpasswdfile, ".ptmp");
+ strcpy(newshadowfile, shadow_file);
+ strcat(newshadowfile, ".ptmp");
+ strcpy(newadjunctfile, adjunct_file);
+ strcat(newadjunctfile, ".ptmp");
+
+ memset(&sa, 0, sizeof (struct sigaction));
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTSTP, &sa, (struct sigaction *)0);
+ sigaction(SIGHUP, &sa, &osa1);
+ sigaction(SIGINT, &sa, &osa2);
+ sigaction(SIGQUIT, &sa, &osa3);
+
+ /* Lock, then open the passwd and shadow files */
+
+ if (yplckpwdf() < 0) {
+ syslog(LOG_ERR,
+ "yppasswdd: Password file(s) busy. "
+ "Try again later.\n");
+ ans = 8;
+ goto cleanup;
+ }
+
+ if ((opwfp = fopen(passwd_file, "r")) == NULL) {
+ syslog(LOG_ERR, "yppasswdd: Could not open %s\n", passwd_file);
+ goto cleanup;
+ }
+
+ fstat(fileno(opwfp), &pwstat);
+
+ if (useshadow) {
+ if ((ospfp = fopen(shadow_file, "r")) == NULL) {
+ syslog(LOG_ERR,
+ "yppasswdd: Could not open %s\n", shadow_file);
+ goto cleanup;
+ }
+
+ fstat(fileno(ospfp), &spstat);
+ }
+
+ if (useadjunct) {
+ if ((oadjfp = fopen(adjunct_file, "r")) == NULL) {
+ syslog(LOG_ERR,
+ "yppasswdd: Could not open %s\n",
+ adjunct_file);
+ goto cleanup;
+ }
+
+ fstat(fileno(oadjfp), &adjstat);
+ }
+
+ /*
+ * Open the new passwd and shadow tmp files,
+ * first with open and then create a FILE * with fdopen()
+ */
+ if ((npwfd = open(newpasswdfile, O_WRONLY | O_CREAT | O_EXCL,
+ pwstat.st_mode)) < 0) {
+ if (errno == EEXIST) {
+ syslog(LOG_WARNING,
+ "yppasswdd: passwd file busy - try again\n");
+ ans = 8;
+ } else {
+ syslog(LOG_ERR, "yppasswdd: %s: %m",
+ newpasswdfile);
+ ans = 9;
+ }
+ goto cleanup;
+ }
+
+ fchown(npwfd, pwstat.st_uid, pwstat.st_gid);
+
+ if ((npwfp = fdopen(npwfd, "w")) == NULL) {
+ syslog(LOG_ERR,
+ "yppasswdd: fdopen() on %s failed\n", newpasswdfile);
+ goto cleanup;
+ }
+
+ if (useshadow) {
+ if ((nspfd = open(newshadowfile, O_WRONLY | O_CREAT | O_EXCL,
+ spstat.st_mode)) < 0) {
+ if (errno == EEXIST) {
+ syslog(LOG_WARNING,
+ "yppasswdd: shadow file busy - try again\n");
+ ans = 8;
+ } else {
+ syslog(LOG_ERR, "yppasswdd: %s: %m",
+ newshadowfile);
+ ans = 9;
+ }
+ goto cleanup;
+ }
+
+ fchown(nspfd, spstat.st_uid, spstat.st_gid);
+
+ if ((nspfp = fdopen(nspfd, "w")) == NULL) {
+ syslog(LOG_ERR,
+ "yppasswdd: fdopen() on %s failed\n",
+ newshadowfile);
+ goto cleanup;
+ }
+ }
+
+ if (useadjunct) {
+ if ((nadjfd = open(newadjunctfile, O_WRONLY | O_CREAT | O_EXCL,
+ adjstat.st_mode)) < 0) {
+ if (errno == EEXIST) {
+ syslog(LOG_WARNING,
+ "yppasswdd: adjunct file busy - try again\n");
+ ans = 8;
+ } else {
+ syslog(LOG_ERR, "yppasswdd: %s: %m",
+ newadjunctfile);
+ ans = 9;
+ }
+ goto cleanup;
+ }
+
+ fchown(nadjfd, adjstat.st_uid, adjstat.st_gid);
+
+ if ((nadjfp = fdopen(nadjfd, "w")) == NULL) {
+ syslog(LOG_ERR,
+ "yppasswdd: fdopen() on %s failed\n",
+ newadjunctfile);
+ goto cleanup;
+ }
+ }
+
+ /*
+ * The following code may not seem all that elegant, but my
+ * interpretation of the man pages relating to the passwd and
+ * shadow files would seem to indicate that there is no guarantee
+ * that the entries contained in those files will be in the same
+ * order...
+ *
+ * So here's the high level overview:
+ *
+ * Loop through the passwd file reading in lines and writing them
+ * out to the new file UNTIL we get to the correct entry.
+ * IF we have a shadow file, loop through it reading in lines and
+ * writing them out to the new file UNTIL we get to the correct
+ * entry. IF we have an adjunct file, loop through it reading in
+ * lines and writing them out to the new file UNTIL we get to the
+ * correct entry.
+ *
+ * Figure out what's changing, contruct the new passwd, shadow,
+ * and adjunct entries and spit em out to the temp files.
+ * At this point, set the done flag and leap back into the loop(s)
+ * until you're finished with the files and then leap to the
+ * section that installs the new files.
+ */
+
+ loop_in_files:
+ /* While we find things in the passwd file */
+ while (fgets(pwbuf, NSS_LINELEN_PASSWD, opwfp)) {
+
+ /*
+ * Is this the passwd entry we want?
+ * If not, then write it out to the new passwd temp file
+ * and remember our position.
+ */
+ if (doneflag || strncmp(name, pwbuf, namelen)) {
+ if (fputs(pwbuf, npwfp) == EOF) {
+ syslog(LOG_ERR,
+ "yppasswdd: write to passwd file failed.\n");
+ goto cleanup;
+ }
+ pwpos = ftell(opwfp);
+ continue;
+ }
+ gotpasswd = 1;
+ break;
+ }
+
+ /* no match */
+ if (!gotpasswd) {
+ syslog(LOG_ERR, "yppasswdd: user %s does not exist\n", name);
+ goto cleanup;
+ }
+
+ /* While we find things in the shadow file */
+ while (useshadow && fgets(spbuf, NSS_LINELEN_SHADOW, ospfp)) {
+
+ /*
+ * Is this the shadow entry that we want?
+ * If not, write it out to the new shadow temp file
+ * and remember our position.
+ */
+ if (doneflag || strncmp(name, spbuf, namelen)) {
+ if (fputs(spbuf, nspfp) == EOF) {
+ syslog(LOG_ERR,
+ "yppasswdd: write to shadow file failed.\n");
+ goto cleanup;
+ }
+ sppos = ftell(ospfp);
+ continue;
+ }
+ gotshadow = 1;
+ break;
+ }
+
+ /* While we find things in the adjunct file */
+ while (useadjunct && fgets(adjbuf, BUFSIZ, oadjfp)) {
+
+ /*
+ * is this the adjunct entry that we want?
+ * If not, write it out to the new temp file
+ * and remember our position.
+ */
+ if (doneflag || strncmp(name, adjbuf, namelen)) {
+ if (fputs(adjbuf, nadjfp) == EOF) {
+ syslog(LOG_ERR,
+ "yppasswdd: write to adjunct file failed.\n");
+ goto cleanup;
+ }
+ continue;
+ }
+ gotadjunct = 1;
+ break;
+ }
+
+ if (doneflag)
+ goto install_files;
+
+ if (useshadow && !gotshadow) {
+ syslog(LOG_ERR, "yppasswdd: no passwd in shadow for %s\n",
+ newpw.pw_name);
+ ans = 4;
+ goto cleanup;
+ }
+ if (useadjunct && !gotadjunct) {
+ syslog(LOG_ERR, "yppasswdd: no passwd in adjunct for %s\n",
+ newpw.pw_name);
+ ans = 4;
+ goto cleanup;
+ }
+
+ /*
+ * Now that we've read in the correct passwd AND
+ * shadow lines, we'll rewind to the beginning of
+ * those lines and let the fget*ent() calls do
+ * the work. Since we are only working with the
+ * first two fields of the adjunct entry, leave
+ * it as a char array.
+ */
+ fseek(opwfp, pwpos, SEEK_SET);
+ opwd = *fgetpwent(opwfp);
+
+ if (useshadow) {
+ fseek(ospfp, sppos, SEEK_SET);
+ ospwd = *fgetspent(ospfp);
+ }
+
+ p = newpw.pw_passwd;
+ if ((!nopw) &&
+ p && *p &&
+ !(*p++ == '#' && *p++ == '#' &&
+ (strcmp(p, opwd.pw_name) == 0)) &&
+ (strcmp(crypt(yppwd.oldpass, newpw.pw_passwd),
+ newpw.pw_passwd) != 0))
+ chpw = 1;
+
+ if ((!noshell) && (strcmp(opwd.pw_shell, newpw.pw_shell) != 0)) {
+ if (single)
+ chpw = 0;
+ chsh = 1;
+ }
+
+ if ((!nogecos) && (strcmp(opwd.pw_gecos, newpw.pw_gecos) != 0)) {
+ if (single) {
+ chpw = 0;
+ chsh = 0;
+ }
+ chgecos = 1;
+ }
+
+ if (!(chpw + chsh + chgecos)) {
+ syslog(LOG_NOTICE, "yppasswdd: no change for %s\n",
+ newpw.pw_name);
+ ans = 3;
+ goto cleanup;
+ }
+
+ if (useshadow && !root_on_master) {
+ if (ospwd.sp_pwdp && *ospwd.sp_pwdp &&
+ (strcmp(crypt(yppwd.oldpass, ospwd.sp_pwdp),
+ ospwd.sp_pwdp) != 0)) {
+
+ syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n",
+ newpw.pw_name);
+ ans = 7;
+ goto cleanup;
+ }
+ } else if (useadjunct) {
+ /*
+ * Clear the adj_encrypt array. Extract the encrypted passwd
+ * into adj_encrypt by setting adj_crypt_begin and
+ * adj_crypt_end to point at the first character of the
+ * encrypted passwd and the first character following the
+ * encrypted passwd in adjbuf, respectively, and copy the
+ * stuff between (there may not be anything) into adj_ecrypt.
+ * Then, check that adj_encrypt contains something and that
+ * the old passwd is correct.
+ */
+ memset(adj_encrypt, 0, sizeof (adj_encrypt));
+ adj_crypt_begin = adjbuf + namelen;
+ adj_crypt_end = strchr(adj_crypt_begin, ':');
+ strncpy(adj_encrypt, adj_crypt_begin,
+ adj_crypt_end - adj_crypt_begin);
+ if (!root_on_master && *adj_encrypt &&
+ (strcmp(crypt(yppwd.oldpass, adj_encrypt),
+ adj_encrypt) != 0)) {
+
+ syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n",
+ newpw.pw_name);
+ ans = 7;
+ goto cleanup;
+ }
+ } else {
+ if (!root_on_master && opwd.pw_passwd && *opwd.pw_passwd &&
+ (strcmp(crypt(yppwd.oldpass, opwd.pw_passwd),
+ opwd.pw_passwd) != 0)) {
+
+ syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n",
+ newpw.pw_name);
+ ans = 7;
+ goto cleanup;
+ }
+ }
+
+#ifdef DEBUG
+ printf("%d %d %d\n", chsh, chgecos, chpw);
+
+ printf("%s %s %s\n",
+ yppwd.newpw.pw_shell,
+ yppwd.newpw.pw_gecos,
+ yppwd.newpw.pw_passwd);
+
+ printf("%s %s %s\n",
+ opwd.pw_shell,
+ opwd.pw_gecos,
+ ospwd.sp_pwdp);
+#endif
+
+ if (chsh && !validloginshell(opwd.pw_shell, newpw.pw_shell,
+ root_on_master)) {
+ goto cleanup;
+ }
+
+ /* security hole fix from original source */
+ for (p = newpw.pw_name; (*p != '\0'); p++)
+ if ((*p == ':') || !(isprint(*p)))
+ *p = '$'; /* you lose buckwheat */
+ for (p = newpw.pw_passwd; (*p != '\0'); p++)
+ if ((*p == ':') || !(isprint(*p)))
+ *p = '$'; /* you lose buckwheat */
+
+ if (chgecos)
+ opwd.pw_gecos = newpw.pw_gecos;
+
+ if (chsh)
+ opwd.pw_shell = newpw.pw_shell;
+
+ /*
+ * If we're changing the shell or gecos fields and we're
+ * using a shadow or adjunct file or not changing the passwd
+ * then go ahead and update the passwd file. The case where
+ * the passwd is being changed and we are not using a shadow
+ * or adjunct file is handled later.
+ */
+ if ((chsh || chgecos) && (useshadow || useadjunct || !chpw) &&
+ putpwent(&opwd, npwfp)) {
+
+ syslog(LOG_ERR, "yppasswdd: putpwent failed: %s\n",
+ passwd_file);
+ goto cleanup;
+ }
+
+ if (chpw) {
+ if (useshadow) {
+ ospwd.sp_pwdp = newpw.pw_passwd;
+ now = DAY_NOW;
+ /* password aging - bug for bug compatibility */
+ if (ospwd.sp_max != -1) {
+ if (now < ospwd.sp_lstchg + ospwd.sp_min) {
+ syslog(LOG_ERR,
+ "yppasswdd: Sorry: < %ld days since "
+ "the last change.\n", ospwd.sp_min);
+ goto cleanup;
+ }
+ }
+ ospwd.sp_lstchg = now;
+ if (putspent(&ospwd, nspfp)) {
+ syslog(LOG_ERR,
+ "yppasswdd: putspent failed: %s\n",
+ shadow_file);
+ goto cleanup;
+ }
+ } else if (useadjunct) {
+ sprintf(adjbuf_new,
+ "%s%s%s", name, newpw.pw_passwd,
+ adj_crypt_end);
+ if (fputs(adjbuf_new, nadjfp) == EOF) {
+ syslog(LOG_ERR,
+ "yppasswdd: write to adjunct failed: %s\n",
+ adjunct_file);
+ goto cleanup;
+ }
+ } else {
+ opwd.pw_passwd = newpw.pw_passwd;
+ if (putpwent(&opwd, npwfp)) {
+ syslog(LOG_ERR,
+ "yppasswdd: putpwent failed: %s\n",
+ passwd_file);
+ goto cleanup;
+ }
+ }
+ }
+
+ if (!doneflag) {
+ doneflag = 1;
+ goto loop_in_files;
+ }
+
+ install_files:
+ /*
+ * Critical section, nothing special needs to be done since we
+ * hold exclusive access to the *.ptmp files
+ */
+ fflush(npwfp);
+ if (useshadow)
+ fflush(nspfp);
+ if (useadjunct)
+ fflush(nadjfp);
+
+ strcpy(tmppasswdfile, passwd_file);
+ strcat(tmppasswdfile, "-");
+ if (useshadow) {
+ strcpy(tmpshadowfile, shadow_file);
+ strcat(tmpshadowfile, "-");
+ }
+ if (useadjunct) {
+ strcpy(tmpadjunctfile, adjunct_file);
+ strcat(tmpadjunctfile, "-");
+ }
+
+ if ((!useshadow && !useadjunct) || (chsh || chgecos)) {
+ if (rename(passwd_file, tmppasswdfile) < 0) {
+ syslog(LOG_CRIT, "yppasswdd: failed to backup "
+ "passwd file: %m");
+ goto cleanup;
+ } else {
+ if (rename(newpasswdfile, passwd_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to mv passwd: %m");
+ if (rename(tmppasswdfile, passwd_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore "
+ "backup of passwd file: %m");
+ }
+ goto cleanup;
+ }
+ }
+ }
+
+ if (useshadow && chpw) {
+ if (rename(shadow_file, tmpshadowfile) < 0) {
+ syslog(LOG_CRIT, "yppasswdd: failed to back up "
+ "shadow file: %m");
+ if (rename(tmppasswdfile, passwd_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore "
+ "backup of passwd file: %m");
+ }
+ goto cleanup;
+ } else {
+ if (rename(newshadowfile, shadow_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to mv shadow: %m");
+ if (rename(tmpshadowfile, shadow_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore "
+ "backup of shadow file: %m");
+ }
+ if (rename(tmppasswdfile, passwd_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore "
+ "backup of passwd file: %m");
+ }
+ goto cleanup;
+ }
+ }
+ } else if (useadjunct && chpw) {
+ if (rename(adjunct_file, tmpadjunctfile) < 0) {
+ syslog(LOG_CRIT, "yppasswdd: failed to back up "
+ "adjunct file: %m");
+ if (rename(tmppasswdfile, passwd_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore backup "
+ "of passwd: %m");
+ }
+ goto cleanup;
+ } else {
+ if (rename(newadjunctfile, adjunct_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppassdd: failed to mv adjunct: %m");
+ if (rename(tmppasswdfile, passwd_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore "
+ "backup of passwd file: %m");
+ }
+ if (rename(tmpadjunctfile, adjunct_file) < 0) {
+ syslog(LOG_CRIT,
+ "yppasswdd: failed to restore "
+ "backup of adjunct file: %m");
+ }
+ goto cleanup;
+ }
+ }
+ }
+
+ if (doneflag)
+ ans = 0;
+ /* End critical section */
+
+ /*
+ * Here we have come only after the new files have been successfully
+ * renamed to original files. At this point, the temp files would still
+ * be existing we need to remove them from the /etc directory
+ */
+ unlink(tmppasswdfile);
+ if (useshadow)
+ unlink(tmpshadowfile);
+ if (useadjunct)
+ unlink(tmpadjunctfile);
+
+ cleanup:
+
+ /* If we don't have opwfp, then we didn't do anything */
+ if (opwfp) {
+ fclose(opwfp);
+
+ if (ospfp) {
+ fclose(ospfp);
+ }
+
+ if (oadjfp) {
+ fclose(oadjfp);
+ }
+
+ unlink(newpasswdfile);
+ /* These tests are cheaper than failing syscalls */
+ if (useshadow)
+ unlink(newshadowfile);
+ if (useadjunct)
+ unlink(newadjunctfile);
+
+ if (npwfp) {
+ fclose(npwfp);
+
+ if (nspfp) {
+ fclose(nspfp);
+ }
+ if (nadjfp) {
+ fclose(nadjfp);
+ }
+ }
+ }
+
+ ypulckpwdf();
+
+ if (doneflag && mflag) {
+ retval = fork();
+ if (retval < 0) {
+ syslog(LOG_ERR, "yppasswdd: Fork failed %m");
+ } else if (retval == 0) {
+ strcpy(cmdbuf, "/usr/ccs/bin/make");
+ for (i = Mstart + 1; i < Argc; i++) {
+ strcat(cmdbuf, " ");
+ strcat(cmdbuf, Argv[i]);
+ }
+
+#ifdef DEBUG
+ syslog(LOG_ERR, "yppasswdd: about to "
+ "execute %s\n", cmdbuf);
+#else
+ if (yplckpwdf() < 0) {
+ syslog(LOG_ERR, "yppasswdd: Couldn't get the"
+ "lock to update the maps");
+ } else {
+ setpgrp();
+ system(cmdbuf);
+ ypulckpwdf();
+ }
+#endif
+ exit(0);
+ }
+ }
+
+ sigaction(SIGHUP, &osa1, (struct sigaction *)0);
+ sigaction(SIGINT, &osa2, (struct sigaction *)0);
+ sigaction(SIGQUIT, &osa3, (struct sigaction *)0);
+
+ if (!svc_sendreply(transp, xdr_int, (char *)&ans))
+ syslog(LOG_WARNING,
+ "yppasswdd: couldn\'t reply to RPC call\n");
+}
diff --git a/usr/src/cmd/ypcmd/yppasswd/passwd.xml b/usr/src/cmd/ypcmd/yppasswd/passwd.xml
new file mode 100644
index 0000000000..763af491e8
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/passwd.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWypr:passwd'>
+
+<service
+ name='network/nis/passwd'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <dependency
+ name='fs'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='rpcbind'
+ grouping='require_all'
+ restart_on='restart'
+ type='service'>
+ <service_fmri value='svc:/network/rpc/bind' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/yp'
+ timeout_seconds='30' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='3' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ NIS (YP) password daemon
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='rpc.yppasswdd' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/ypcmd/yppasswd/yplckpwdf.c b/usr/src/cmd/ypcmd/yppasswd/yplckpwdf.c
new file mode 100644
index 0000000000..1e6e1de4b4
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/yplckpwdf.c
@@ -0,0 +1,95 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h> /* alarm() */
+
+#define S_WAITTIME 15
+
+static struct flock flock = {
+ 0, /* l_type */
+ 0, /* l_whence */
+ 0, /* l_start */
+ 0, /* l_len */
+ 0, /* l_sysid */
+ 0 /* l_pid */
+ };
+
+/*
+ * yplckpwdf() returns a 0 for a successful lock within W_WAITTIME
+ * and -1 otherwise
+ */
+
+static int fildes = -1;
+extern char lockfile[];
+
+/* ARGSUSED */
+static void
+almhdlr(int sig)
+{
+}
+
+int
+yplckpwdf()
+{
+ int retval;
+ if ((fildes = creat(lockfile, 0600)) == -1)
+ return (-1);
+
+ flock.l_type = F_WRLCK;
+ (void) sigset(SIGALRM, almhdlr);
+ (void) alarm(S_WAITTIME);
+ retval = fcntl(fildes, F_SETLKW, (int)&flock);
+ (void) alarm(0);
+ (void) sigset(SIGALRM, SIG_DFL);
+ return (retval);
+
+}
+
+/*
+ * ypulckpwdf() returns 0 for a successful unlock and -1 otherwise
+ */
+int
+ypulckpwdf()
+{
+ if (fildes == -1)
+ return (-1);
+
+ flock.l_type = F_UNLCK;
+ (void) fcntl(fildes, F_SETLK, (int)&flock);
+ (void) close(fildes);
+ fildes = -1;
+ return (0);
+
+}
diff --git a/usr/src/cmd/ypcmd/yppasswd/yppasswdd.c b/usr/src/cmd/ypcmd/yppasswd/yppasswdd.c
new file mode 100644
index 0000000000..e299ab32c4
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/yppasswdd.c
@@ -0,0 +1,661 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <syslog.h>
+#include <crypt.h>
+#include <errno.h>
+#include <tiuser.h>
+#include <netdir.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netconfig.h>
+#include <deflt.h>
+
+/* N2L includes */
+#include <ndbm.h>
+#include "shim.h"
+#include "yptol.h"
+
+/* must match sizes in passwd */
+#define STRSIZE 100
+
+#define DEFDIR "/etc/"
+#define MYPASSWD "passwd"
+#define MYSHADOW "shadow"
+#define DEFAULT_YPPASSWDD "/etc/default/yppasswdd"
+#define YPPASSWDD_STR "check_restricted_shell_name=1"
+
+/* The guts are in there */
+extern changepasswd(SVCXPRT *);
+
+static void boilerplate(struct svc_req *rqstp, SVCXPRT *transp);
+static void unlimit(int lim);
+bool_t validloginshell(char *sh, char *arg, int);
+int validstr(char *str, size_t size);
+
+extern char *getusershell(void);
+extern void setusershell(void);
+extern void endusershell(void);
+
+int Argc;
+char **Argv;
+int mflag; /* do a make */
+int Mstart;
+int single = 0;
+int nogecos = 0;
+int noshell = 0;
+int nopw = 0;
+int useadjunct = 0;
+int useshadow = 0;
+
+static char *defshell = "/bin/sh";
+
+/* These are the various reasons we might exit. */
+enum exitstat {
+ Esuccess,
+ EminusDandfiles,
+ Emissingdir,
+ Emissingadjunct,
+ Eaccesspasswd,
+ Eaccessshadow,
+ Echdir,
+ Egetnetconfigent,
+ Et_open,
+ Enetdir_rsvdport,
+ Et_sync,
+ Et_info,
+ Esvc_create,
+ Esvc_reg,
+ Esvcrun_ret,
+ ElockFail,
+ EparseFail
+};
+
+static char err_usage[] =
+"Usage:\n"
+" rpc.yppasswdd [-D directory | passwd [passwd.adjunct]]\n"
+" [-nopw] [-nogecos]\n"
+" [-noshell] [-m arg1 arg2 ...]\n"
+"where\n"
+" directory is the directory where the passwd, shadow and/or\n"
+" passwd.adjunct files are found (/etc by default)\n"
+" It should match the setting of PWDIR in /var/yp/Makefile\n\n"
+" Alternatively, the old 4.1.x syntax is supported where\n"
+" passwd is the path to the passwd file\n"
+" passwd.adjunct is the patch to the passwd.adjunct file\n"
+" NOTES:\n"
+" 1. The -D option and the passwd/passwd.adjunct arguments are\n"
+" mutually exclusive\n"
+" 2. The old syntax deprecated and will be removed in a future\n"
+" release\n"
+" 3. A shadow file found in the same directory as the passwd\n"
+" will be assumed to contain the password information\n\n"
+" arguments after -m are passed to make(1S) after password changes\n"
+" -nopw passwords may not be changed remotely using passwd\n"
+" -nogecos full name may not be changed remotely using passwd or chfn\n"
+" -noshell shell may not be changed remotely using passwd or chsh\n";
+
+char passwd_file[FILENAME_MAX], shadow_file[FILENAME_MAX];
+char lockfile[FILENAME_MAX], adjunct_file[FILENAME_MAX];
+
+int
+main(int argc, char **argv)
+{
+ SVCXPRT *transp4, *transp6, *transpl;
+ struct netconfig *nconf4, *nconf6, *nconfl;
+ int i, tli4, tli6, stat;
+ int errorflag;
+ int dfexcl; /* -D or files, not both flag */
+ enum exitstat exitstatus = Esuccess;
+ int connmaxrec = RPC_MAXDATASIZE;
+
+ strcpy(passwd_file, DEFDIR MYPASSWD);
+ strcpy(shadow_file, DEFDIR MYSHADOW);
+ strcpy(lockfile, DEFDIR ".pwd.lock");
+ strcpy(adjunct_file, DEFDIR "security/passwd.adjunct");
+
+ Argc = argc;
+ Argv = argv;
+
+ for (i = 1, errorflag = 0, dfexcl = 0; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == 'm') {
+ if (access("/usr/ccs/bin/make", X_OK) < 0)
+ fprintf(stderr,
+ "%s: /usr/ccs/bin/make is not available, "
+ "ignoring -m option",
+ argv[0]);
+ else {
+ mflag++;
+ Mstart = i;
+ break;
+ }
+ } else if (argv[i][0] == '-' && argv[i][1] == 'D') {
+ switch (dfexcl) {
+ case 0:
+ if (++i < argc) {
+ strcpy(passwd_file, argv[i]);
+ strcpy(shadow_file, argv[i]);
+ strcpy(adjunct_file, argv[i]);
+ strcpy(lockfile, argv[i]);
+ if (argv[i][strlen(argv[i]) - 1] == '/') {
+ strcat(passwd_file, MYPASSWD);
+ strcat(shadow_file, MYSHADOW);
+ strcat(lockfile, ".pwd.lock");
+ strcat(adjunct_file, "security/passwd.adjunct");
+ } else {
+ strcat(passwd_file, "/" MYPASSWD);
+ strcat(shadow_file, "/" MYSHADOW);
+ strcat(lockfile, "/.pwd.lock");
+ strcat(adjunct_file,
+ "/security/passwd.adjunct");
+ }
+ dfexcl++;
+ } else {
+ fprintf(stderr,
+ "rpc.yppasswdd: -D option requires a "
+ "directory argument\n");
+ errorflag++;
+ exitstatus = Emissingdir;
+ }
+ break;
+ case 1:
+ fprintf(stderr,
+ "rpc.yppasswdd: cannot specify passwd/"
+ "passwd.adjunct pathnames AND use -D\n");
+ errorflag++;
+ dfexcl++;
+ exitstatus = EminusDandfiles;
+ break;
+ default:
+ break;
+ }
+ /* -single: Allow user to change only one of password, */
+ /* shell, or full name at a time. (WHY?) */
+ /* else if (strcmp(argv[i], "-single") == 0) */
+ /* single = 1; */
+ /* else if (strcmp(argv[i], "-nosingle") == 0) */
+ /* single = 0; */
+ } else if (strcmp(argv[i], "-nogecos") == 0)
+ nogecos = 1;
+ else if (strcmp(argv[i], "-nopw") == 0)
+ nopw = 1;
+ else if (strcmp(argv[i], "-noshell") == 0)
+ noshell = 1;
+ else if (argv[i][0] != '-') {
+ /*
+ * If we find a shadow file, we warn that we're
+ * using it in addition to warning that the user
+ * it using a deprecated syntax.
+ */
+ errorflag++;
+ switch (dfexcl) {
+ case 0:
+ strcpy(passwd_file, argv[i]);
+ memset(shadow_file, 0, sizeof (shadow_file));
+ strncpy(shadow_file, argv[i],
+ strrchr(argv[i], '/') - argv[i] + 1);
+ strcat(shadow_file, MYSHADOW);
+ fprintf(stderr,
+ "rpc.yppasswdd: specifying the password file"
+ " on the command line is \n"
+ " obsolete, "
+ "consider using the -D option instead.\n");
+ if (access(shadow_file, F_OK) == 0) {
+ fprintf(stderr,
+ "rpc.yppasswdd: found a shadow file in "
+ "the same directory as %s\n"
+ " It will be used.\n",
+ passwd_file);
+ }
+ if (i + 1 < argc && argv[i+1][0] != '-') {
+ strcpy(adjunct_file, argv[++i]);
+ if (access(adjunct_file, F_OK) != 0) {
+ fprintf(stderr,
+ "rpc.yppasswdd: adjunct file %s "
+ "not found\n",
+ adjunct_file);
+ exitstatus = Emissingadjunct;
+ }
+ }
+ dfexcl++;
+ break;
+ case 1:
+ fprintf(stderr,
+ "rpc.yppasswdd: cannot specify passwd/"
+ "passwd.adjunct pathnames AND use -D\n");
+ dfexcl++;
+ exitstatus = EminusDandfiles;
+ break;
+ default:
+ break;
+ }
+ } else {
+ errorflag++;
+ fprintf(stderr,
+ "rpc.yppasswdd: unrecognized option %s ignored\n",
+ argv[i]);
+ }
+ }
+
+ if (errorflag)
+ fprintf(stderr, err_usage);
+
+ if (exitstatus)
+ exit(exitstatus);
+
+ if (access(passwd_file, W_OK) < 0) {
+ fprintf(stderr, "rpc.yppasswdd: can't access %s\n",
+ passwd_file);
+ exitstatus = Eaccesspasswd;
+ }
+ if (access(shadow_file, W_OK) == 0) {
+ useshadow = 1;
+ } else {
+ /* We don't demand a shadow file unless we're looking at /etc */
+ if (strcmp(DEFDIR MYSHADOW, shadow_file) == 0) {
+ fprintf(stderr, "rpc.yppasswdd: can't access %s\n",
+ shadow_file);
+ exitstatus = Eaccessshadow;
+ }
+ }
+ if (access(adjunct_file, W_OK) == 0) {
+ /* using an adjunct file */
+ useadjunct = 1;
+ }
+
+ if (chdir("/var/yp") < 0) {
+ fprintf(stderr, "rpc.yppasswdd: can't chdir to /var/yp\n");
+ exitstatus = Echdir;
+ }
+
+ if (exitstatus)
+ exit(exitstatus);
+
+ if (errorflag)
+ fprintf(stderr, "\nProceeding.\n");
+
+
+ /*
+ * Initialize locking system.
+ * This is required for N2L version which accesses the DBM files.
+ * For the non N2L version this sets up some locking which, since non
+ * N2L mode does not access the DBM files, will be unused.
+ *
+ * This also sets up yptol_mode.
+ */
+ if (!init_lock_system(TRUE)) {
+ fprintf(stderr,
+ "rpc.yppasswdd: Cant initialize locking system\n");
+ exit(ElockFail);
+ }
+
+#ifndef DEBUG
+ /* Close everything, but stdin/stdout/stderr */
+ closefrom(3);
+#endif
+
+ if (yptol_mode) {
+ stat = parseConfig(NULL, NTOL_MAP_FILE);
+ if (stat == 1) {
+ fprintf(stderr, "yppasswdd : NIS to LDAP mapping"
+ " inactive.\n");
+ } else if (stat != 0) {
+ fprintf(stderr, "yppasswdd : Aborting after NIS to LDAP"
+ " mapping error.\n");
+ exit(EparseFail);
+ }
+ }
+
+#ifndef DEBUG
+ /* Wack umask that we inherited from parent */
+ umask(0);
+
+ /* Be a midwife to ourselves */
+ if (fork())
+ exit(Esuccess);
+
+ /* Disassociation is hard to do, la la la */
+ setpgrp();
+ setsid();
+
+ /* Ignore stuff */
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGWINCH, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
+ /*
+ * Just in case that wasn't enough, let's fork
+ * again. (per Stevens).
+ */
+ if (fork())
+ exit(Esuccess);
+
+ /*
+ * We need stdin, stdout, and stderr later when we
+ * fork a make(1).
+ */
+ freopen("/dev/null", "r+", stdin);
+ freopen("/dev/null", "r+", stdout);
+ freopen("/dev/null", "r+", stderr);
+#endif
+
+ openlog("yppasswdd", LOG_CONS | LOG_PID, LOG_AUTH);
+ unlimit(RLIMIT_CPU);
+ unlimit(RLIMIT_FSIZE);
+
+ /*
+ * Set non-blocking mode and maximum record size for
+ * connection oriented RPC transports.
+ */
+ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
+ syslog(LOG_INFO, "unable to set maximum RPC record size");
+ }
+
+ nconf4 = getnetconfigent("udp");
+ nconf6 = getnetconfigent("udp6");
+ if (nconf4 == 0 && nconf6 == 0) {
+ syslog(LOG_ERR, "udp/udp6 transport not supported\n");
+ exit(Egetnetconfigent);
+ }
+
+ tli4 = (nconf4 != 0) ? t_open(nconf4->nc_device, O_RDWR, NULL) : -1;
+ tli6 = (nconf6 != 0) ? t_open(nconf6->nc_device, O_RDWR, NULL) : -1;
+
+ if (tli4 == -1 && tli6 == -1) {
+ syslog(LOG_ERR, "can\'t open TLI endpoint(s)\n");
+ exit(Et_open);
+ }
+
+ if (tli4 != -1) {
+ if (netdir_options(nconf4, ND_SET_RESERVEDPORT, tli4, NULL)) {
+ syslog(LOG_ERR, "could not set reserved port: %s\n",
+ netdir_sperror());
+ exit(Enetdir_rsvdport);
+ }
+ }
+ if (tli6 != -1) {
+ if (netdir_options(nconf6, ND_SET_RESERVEDPORT, tli6, NULL)) {
+ syslog(LOG_ERR, "could not set reserved port: %s\n",
+ netdir_sperror());
+ exit(Enetdir_rsvdport);
+ }
+ }
+#ifdef DEBUG
+ {
+ int i, tli[2];
+ char *label[2] = {"udp", "udp6"};
+ int state;
+ struct t_info tinfo;
+
+ tli[0] = tli4;
+ tli[1] = tli6;
+
+ for (i = 0; i < sizeof (tli)/sizeof (tli[0]); i++) {
+ fprintf(stderr, "transport %s, fd = %d\n",
+ tli[i], label[i]);
+ if ((state = t_sync(tli[i])) < 0) {
+ fprintf(stderr, "t_sync failed: %s\n",
+ t_errlist[t_errno]);
+ exit(Et_sync);
+ }
+ if (t_getinfo(tli[i], &tinfo) < 0) {
+ fprintf(stderr, "t_getinfo failed: %s\n",
+ t_errlist[t_errno]);
+ exit(Et_info);
+ }
+
+ switch (state) {
+ case T_UNBND:
+ fprintf(stderr, "TLI is unbound\n");
+ break;
+ case T_IDLE:
+ fprintf(stderr, "TLI is idle\n");
+ break;
+ case T_INREL:
+ fprintf(stderr,
+ "other side wants to release\n");
+ break;
+ case T_INCON:
+ fprintf(stderr, "T_INCON\n");
+ break;
+ case T_DATAXFER:
+ fprintf(stderr, "T_DATAXFER\n");
+ break;
+ default:
+ fprintf(stderr, "no state info, state = %d\n",
+ state);
+ }
+ }
+ }
+#endif
+ if (tli4 != -1) {
+ rpcb_unset((ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS,
+ nconf4);
+ transp4 = svc_tli_create(tli4, nconf4, NULL, 0, 0);
+ } else {
+ transp4 = 0;
+ }
+ if (tli6 != -1) {
+ rpcb_unset((ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS,
+ nconf6);
+ transp6 = svc_tli_create(tli6, nconf6, NULL, 0, 0);
+ } else {
+ transp6 = 0;
+ }
+ if (transp4 == 0 && transp6 == 0) {
+ syslog(LOG_ERR, "yppasswdd: couldn't create an RPC server\n");
+ exit(Esvc_create);
+ }
+ if (transp4 && !svc_reg(transp4, (ulong_t)YPPASSWDPROG,
+ (ulong_t)YPPASSWDVERS, boilerplate, nconf4)) {
+ syslog(LOG_ERR, "yppasswdd: couldn't register yppasswdd\n");
+ exit(Esvc_reg);
+ }
+ if (transp6 && !svc_reg(transp6, (ulong_t)YPPASSWDPROG,
+ (ulong_t)YPPASSWDVERS, boilerplate, nconf6)) {
+ syslog(LOG_ERR, "yppasswdd: couldn't register yppasswdd\n");
+ exit(Esvc_reg);
+ }
+
+ /*
+ * Create a loopback RPC service for secure authentication of local
+ * principals -- we need this for accepting passwd updates from
+ * root on the master server.
+ */
+ if ((nconfl = getnetconfigent("ticlts")) == NULL) {
+ syslog(LOG_ERR, "transport ticlts not supported\n");
+ exit(Egetnetconfigent);
+ }
+ rpcb_unset((ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS, nconfl);
+ transpl = svc_tli_create(RPC_ANYFD, nconfl, NULL, 0, 0);
+ if (transpl == NULL) {
+ syslog(LOG_ERR,
+ "yppasswdd: couldn't create an loopback RPC server\n");
+ exit(Esvc_create);
+ }
+ if (!svc_reg(transpl, (ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS,
+ boilerplate, nconfl)) {
+ syslog(LOG_ERR, "yppasswdd: couldn't register yppasswdd\n");
+ exit(Esvc_reg);
+ }
+ __rpc_negotiate_uid(transpl->xp_fd);
+ freenetconfigent(nconf4);
+ freenetconfigent(nconf6);
+ freenetconfigent(nconfl);
+ svc_run();
+ syslog(LOG_ERR, "yppasswdd: svc_run shouldn't have returned\n");
+
+ return (Esvcrun_ret);
+ /* NOTREACHED */
+}
+
+static void
+boilerplate(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ if (!svc_sendreply(transp, xdr_void, (char *)0))
+ syslog(LOG_WARNING,
+ "yppasswdd: couldn't reply to RPC call\n");
+ break;
+ case YPPASSWDPROC_UPDATE:
+ if (yptol_mode)
+ shim_changepasswd(transp);
+ else
+ changepasswd(transp);
+ break;
+ }
+}
+
+int
+validstr(char *str, size_t size)
+{
+ char c;
+
+ if (str == NULL || strlen(str) > size || strchr(str, ':'))
+ return (0);
+ while (c = *str++) {
+ if (iscntrl(c))
+ return (0);
+ }
+ return (1);
+}
+
+bool_t
+validloginshell(char *pw_shell, char *arg, int privileged)
+{
+ static char newshell[STRSIZE];
+ char *cp, *valid;
+
+ if (pw_shell == 0 || *pw_shell == '\0')
+ pw_shell = defshell;
+
+ if ((defopen(DEFAULT_YPPASSWDD)) == 0) {
+ if ((defread(YPPASSWDD_STR)) != NULL) {
+ cp = strrchr(pw_shell, '/');
+ if (cp)
+ cp++;
+ else
+ cp = pw_shell;
+
+ if (*cp == 'r') {
+ syslog(LOG_ERR,
+ "yppasswdd: cannot change "
+ "from restricted shell %s\n",
+ pw_shell);
+ return (0);
+ }
+ }
+ (void) defopen((char *)NULL);
+ }
+
+ for (valid = getusershell(); valid; valid = getusershell())
+ if (strcmp(pw_shell, valid) == 0)
+ break;
+
+ if (valid == NULL && !privileged) {
+ syslog(LOG_ERR, "yppasswdd: Current shell is not valid: %s\n",
+ pw_shell);
+ endusershell();
+ return (0);
+ }
+
+ if (arg != 0) {
+ strncpy(newshell, arg, sizeof (newshell) - 1);
+ newshell[sizeof (newshell) - 1] = 0;
+ } else {
+ endusershell();
+ return (0);
+ }
+
+ /*
+ * Allow user to give shell name w/o preceding pathname.
+ */
+ setusershell();
+ for (valid = getusershell(); valid; valid = getusershell()) {
+ if (newshell[0] == '/') {
+ cp = valid;
+ } else {
+ cp = strrchr(valid, '/');
+ if (cp == 0)
+ cp = valid;
+ else
+ cp++;
+ }
+ if (strcmp(newshell, cp) == 0)
+ break;
+ }
+
+ if (valid == 0) {
+ if (!privileged || newshell[0] != '/') {
+ syslog(LOG_WARNING,
+ "%s is unacceptable as a new shell.\n",
+ newshell);
+ endusershell();
+ return (0);
+ }
+ valid = newshell;
+ }
+
+ if (access(valid, X_OK) < 0) {
+ syslog(LOG_WARNING, "%s is unavailable.\n", valid);
+ endusershell();
+ return (0);
+ }
+
+ strncpy(newshell, valid, sizeof (newshell));
+ pw_shell = newshell;
+ endusershell();
+ return (1);
+}
+
+static void
+unlimit(int lim)
+{
+ struct rlimit rlim;
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ setrlimit(lim, &rlim);
+}
diff --git a/usr/src/cmd/ypcmd/yppasswd/yppasswdd.dfl b/usr/src/cmd/ypcmd/yppasswd/yppasswdd.dfl
new file mode 100644
index 0000000000..4fb4401ef0
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/yppasswdd.dfl
@@ -0,0 +1,34 @@
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# defaults file for yppasswdd
+#
+# The following enables a check when a user tries to change shells
+# using passwd -e. If the following line is uncommented, then
+# shells beginning with the letter 'r' are considered "restricted"
+# and the users with such shells cannot change their shell. The
+# checks described in getusershell(3C) apply either way.
+#
+#check_restricted_shell_name=1
diff --git a/usr/src/cmd/ypcmd/yppasswd/yppasswdxdr.c b/usr/src/cmd/ypcmd/yppasswd/yppasswdxdr.c
new file mode 100644
index 0000000000..6bb83acf36
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppasswd/yppasswdxdr.c
@@ -0,0 +1,72 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* mods by OpCom */
+
+#include <rpc/rpc.h>
+#include <rpcsvc/yppasswd.h>
+
+extern bool_t xdr_uid_t(XDR *, uid_t *);
+extern bool_t xdr_gid_t(XDR *, gid_t *);
+
+bool_t
+xdr_passwd(XDR *xdrs, struct passwd *pw)
+{
+ if (!xdr_wrapstring(xdrs, &pw->pw_name)) {
+ return (FALSE);
+ }
+ if (!xdr_wrapstring(xdrs, &pw->pw_passwd)) {
+ return (FALSE);
+ }
+ if (!xdr_uid_t(xdrs, &pw->pw_uid)) {
+ return (FALSE);
+ }
+ if (!xdr_gid_t(xdrs, (&pw->pw_gid))) {
+ return (FALSE);
+ }
+ if (!xdr_wrapstring(xdrs, &pw->pw_gecos)) {
+ return (FALSE);
+ }
+ if (!xdr_wrapstring(xdrs, &pw->pw_dir)) {
+ return (FALSE);
+ }
+ if (!xdr_wrapstring(xdrs, &pw->pw_shell)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_yppasswd(XDR *xdrs, struct yppasswd *yppw)
+{
+ if (!xdr_wrapstring(xdrs, &yppw->oldpass)) {
+ return (FALSE);
+ }
+ if (!xdr_passwd(xdrs, &yppw->newpw)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
diff --git a/usr/src/cmd/ypcmd/yppoll.c b/usr/src/cmd/ypcmd/yppoll.c
new file mode 100644
index 0000000000..287ba42730
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppoll.c
@@ -0,0 +1,384 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1995 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a user command which asks a particular ypserv which version of a
+ * map it is using. Usage is:
+ *
+ * yppoll [-h <host>] [-d <domainname>] mapname
+ *
+ * If the host is ommitted, the local host will be used. If host is specified
+ * as an internet address, no yp services need to be locally available.
+ *
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#include <netdir.h>
+#include <arpa/inet.h>
+#include "yp_b.h"
+
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0
+
+#define TIMEOUT 30 /* Total seconds for timeout */
+
+static int status = 0; /* exit status */
+static char *domain = NULL;
+static char default_domain_name[YPMAXDOMAIN];
+static char *map = NULL;
+static char *host = NULL;
+static char default_host_name[256];
+
+static char err_usage[] =
+"Usage:\n\
+ yppoll [ -h host ] [ -d domainname ] mapname\n\n";
+static char err_bad_args[] =
+ "Bad %s argument.\n";
+static char err_cant_get_kname[] =
+ "Can't get %s back from system call.\n";
+static char err_null_kname[] =
+ "%s hasn't been set on this machine.\n";
+static char err_bad_hostname[] = "hostname";
+static char err_bad_mapname[] = "mapname";
+static char err_bad_domainname[] = "domainname";
+static char err_bad_resp[] =
+ "Ill-formed response returned from ypserv on host %s.\n";
+
+static void get_command_line_args();
+static void getdomain();
+static void getlochost();
+static void getmapparms();
+static void newresults();
+static void getypserv();
+
+extern void exit();
+extern int getdomainname();
+extern int gethostname();
+extern unsigned int strlen();
+extern int strcmp();
+
+/*
+ * This is the mainline for the yppoll process.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+
+{
+ get_command_line_args(argc, argv);
+
+ if (!domain) {
+ getdomain();
+ }
+
+ if (!host) {
+ getypserv();
+ }
+
+ getmapparms();
+ exit(status);
+ /* NOTREACHED */
+}
+
+/*
+ * This does the command line argument processing.
+ */
+static void
+get_command_line_args(argc, argv)
+ int argc;
+ char **argv;
+
+{
+ argv++;
+
+ while (--argc) {
+
+ if ((*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+
+ case 'h':
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ host = *argv;
+ argv++;
+
+ if ((int)strlen(host) > 256) {
+ (void) fprintf(stderr,
+ err_bad_args,
+ err_bad_hostname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ break;
+
+ case 'd':
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+ argv++;
+
+ if ((int)strlen(domain) > YPMAXDOMAIN) {
+ (void) fprintf(stderr,
+ err_bad_args,
+ err_bad_domainname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ break;
+
+ default:
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+
+ }
+
+ } else {
+ if (!map) {
+ map = *argv;
+
+ if ((int)strlen(map) > YPMAXMAP) {
+ (void) fprintf(stderr, err_bad_args,
+ err_bad_mapname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+ }
+ }
+
+ if (!map) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+}
+
+/*
+ * This gets the local default domainname, and makes sure that it's set
+ * to something reasonable. domain is set here.
+ */
+static void
+getdomain()
+{
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ (void) fprintf(stderr, err_cant_get_kname, err_bad_domainname);
+ exit(1);
+ }
+
+ if ((int)strlen(domain) == 0) {
+ (void) fprintf(stderr, err_null_kname, err_bad_domainname);
+ exit(1);
+ }
+}
+
+/*
+ * This gets the local hostname back from the kernel
+ */
+static void
+getlochost()
+{
+
+ if (! gethostname(default_host_name, 256)) {
+ host = default_host_name;
+ } else {
+ (void) fprintf(stderr, err_cant_get_kname, err_bad_hostname);
+ exit(1);
+ }
+}
+
+static void
+getmapparms()
+{
+ CLIENT * map_clnt;
+ struct ypresp_order oresp;
+ struct ypreq_nokey req;
+ struct ypresp_master mresp;
+ struct ypresp_master *mresults = (struct ypresp_master *) NULL;
+ struct ypresp_order *oresults = (struct ypresp_order *) NULL;
+
+ struct timeval timeout;
+ enum clnt_stat s;
+
+ if ((map_clnt = clnt_create(host, YPPROG, YPVERS,
+ "netpath")) == NULL) {
+ (void) fprintf(stderr,
+ "Can't create connection to %s.\n", host);
+ clnt_pcreateerror("Reason");
+ exit(1);
+ }
+
+ timeout.tv_sec = TIMEOUT;
+ timeout.tv_usec = 0;
+ req.domain = domain;
+ req.map = map;
+ mresp.master = NULL;
+
+ if (clnt_call(map_clnt, YPPROC_MASTER, (xdrproc_t)xdr_ypreq_nokey,
+ (caddr_t) &req, (xdrproc_t)xdr_ypresp_master,
+ (caddr_t) &mresp, timeout) == RPC_SUCCESS) {
+ mresults = &mresp;
+ s = (enum clnt_stat) clnt_call(map_clnt, YPPROC_ORDER,
+ (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
+ (xdrproc_t)xdr_ypresp_order, (char *)&oresp, timeout);
+
+ if (s == RPC_SUCCESS) {
+ oresults = &oresp;
+ newresults(mresults, oresults);
+ } else {
+ (void) fprintf(stderr,
+ "Can't make YPPROC_ORDER call to ypserv at %s.\n ",
+ host);
+ clnt_perror(map_clnt, "Reason");
+ exit(1);
+ }
+
+ } else {
+ clnt_destroy(map_clnt);
+ }
+}
+
+static void
+newresults(m, o)
+ struct ypresp_master *m;
+ struct ypresp_order *o;
+{
+ char *s_domok = "Domain %s is supported.\n";
+ char *s_ook = "Map %s has order number %d.\n";
+ char *s_mok = "The master server is %s.\n";
+ char *s_mbad = "Can't get master for map %s.\n Reason: %s\n";
+ char *s_obad = "Can't get order number for map %s.\n Reason: %s\n";
+
+ if (m->status == YP_TRUE && o->status == YP_TRUE) {
+ (void) printf(s_domok, domain);
+ (void) printf(s_ook, map, o->ordernum);
+ (void) printf(s_mok, m->master);
+ } else if (o->status == YP_TRUE) {
+ (void) printf(s_domok, domain);
+ (void) printf(s_ook, map, o->ordernum);
+ (void) fprintf(stderr, s_mbad, map,
+ yperr_string(ypprot_err(m->status)));
+ status = 1;
+ } else if (m->status == YP_TRUE) {
+ (void) printf(s_domok, domain);
+ (void) fprintf(stderr, s_obad, map,
+ yperr_string(ypprot_err(o->status)));
+ (void) printf(s_mok, m->master);
+ status = 1;
+ } else {
+ (void) fprintf(stderr,
+ "Can't get any map parameter information.\n");
+ (void) fprintf(stderr, s_obad, map,
+ yperr_string(ypprot_err(o->status)));
+ (void) fprintf(stderr, s_mbad, map,
+ yperr_string(ypprot_err(m->status)));
+ status = 1;
+ }
+}
+
+static void
+getypserv()
+{
+ struct ypbind_resp response;
+ struct ypbind_domain ypdomain;
+ struct ypbind_binding *binding;
+ static char hostbuf[256];
+
+ getlochost();
+
+ (void) memset((char *)&response, 0, sizeof (response));
+ ypdomain.ypbind_domainname = domain;
+ ypdomain.ypbind_vers = YPBINDVERS;
+ (void) rpc_call(host, YPBINDPROG, YPBINDVERS, YPBINDPROC_DOMAIN,
+ xdr_ypbind_domain, (char *)&ypdomain, xdr_ypbind_resp,
+ (char *)&response, "netpath");
+ if (response.ypbind_status != YPBIND_SUCC_VAL) {
+ (void) fprintf(stderr, "couldn't get yp server - status %u\n",
+ response.ypbind_status);
+ exit(1);
+ }
+ binding = response.ypbind_resp_u.ypbind_bindinfo;
+ host = binding->ypbind_servername;
+
+ /*
+ * When ypbind is running in broadcast mode, it sets the
+ * servername to "". To get the real name of the server,
+ * we need to do a host lookup on the svcaddr. This code
+ * is similar to code in ypwhich.
+ */
+ if (strcmp(host, "") == 0) {
+ struct nd_hostservlist *nhs;
+ struct netconfig *nconf = binding->ypbind_nconf;
+ struct netbuf *svcaddr = binding->ypbind_svcaddr;
+
+ if (netdir_getbyaddr(nconf, &nhs, svcaddr) != ND_OK) {
+ struct sockaddr_in *sa;
+
+ sa = (struct sockaddr_in *)svcaddr->buf;
+
+ strcpy(hostbuf, inet_ntoa(sa->sin_addr));
+ } else {
+ sprintf(hostbuf, "%s", nhs->h_hostservs->h_host);
+ }
+ host = hostbuf;
+ netdir_free((char *)nhs, ND_HOSTSERVLIST);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/yppush.c b/usr/src/cmd/ypcmd/yppush.c
new file mode 100644
index 0000000000..441e546763
--- /dev/null
+++ b/usr/src/cmd/ypcmd/yppush.c
@@ -0,0 +1,1102 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+ * All Rights Reserved
+ *
+ * Portions of this source code were derived from Berkeley
+ * 4.3 BSD under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define _SVID_GETTOD
+#include <sys/time.h>
+extern int gettimeofday(struct timeval *);
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <signal.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/rpcb_clnt.h>
+#include <sys/systeminfo.h>
+#include <sys/select.h>
+#include "ypsym.h"
+#include "ypdefs.h"
+#include "yp_b.h"
+#include "shim.h"
+#include "yptol.h"
+
+
+#ifdef DEBUG
+#undef YPPROG
+#define YPPROG ((ulong_t)109999)
+#undef YPBINDPROG
+#define YPBINDPROG ((ulong_t)109998)
+#endif
+
+#define INTER_TRY 12 /* Seconds between tries */
+#define PORTMAP_TIME 30 /* Seconds before decide its down */
+#define TIMEOUT INTER_TRY*4 /* Total time for timeout */
+#define CUR_PAR 4 /* Total parallal yppushes */
+#define MIN_GRACE 25 /* select timeout and minimum grace */
+#define GRACE_PERIOD 800 /* Total seconds we'll wait for */
+ /* responses from ypxfrs, yes */
+ /* virginia yp map transfers */
+ /* can take a long time, we */
+ /* only worry if the slave */
+ /* crashes ... */
+
+USE_YPDBPATH
+static char *pusage;
+static char *domain = NULL;
+static char *host = NULL;
+static char my_name[YPMAXPEER +1];
+static char default_domain_name[YPMAXDOMAIN];
+static char domain_alias[MAXNAMLEN]; /* nickname for domain - */
+ /* used in sysv filesystems */
+static char map_alias[MAXNAMLEN]; /* nickname for map - */
+ /* used in sysv filesystems */
+static char *map = NULL;
+static bool verbose = FALSE;
+static bool onehost = FALSE;
+static bool oldxfr = FALSE;
+static bool callback_timeout = FALSE; /* set when a callback times out */
+int grace_period = GRACE_PERIOD;
+int curpar = CUR_PAR; /* should be set by other stuff */
+static char ypmapname[1024]; /* Used to check for map's existence */
+
+static struct timeval intertry = {
+ INTER_TRY, /* Seconds */
+ 0 /* Microseconds */
+};
+static struct timeval timeout = {
+ TIMEOUT, /* Seconds */
+ 0 /* Microseconds */
+};
+static SVCXPRT *transport4;
+static SVCXPRT *transport6;
+struct server {
+ struct server *pnext;
+ struct dom_binding domb;
+ char svc_name[YPMAXPEER+1];
+ unsigned long xactid;
+ unsigned short state;
+ unsigned long status;
+ bool oldvers;
+ int start_time;
+};
+#define n_conf dom_binding->ypbind_nconf
+#define svc_addr dom_binding->ypbind_svcaddr
+static struct server *server_list = (struct server *)NULL;
+static struct server *active_list = (struct server *)NULL;
+
+/* State values for server.state field */
+
+#define SSTAT_INIT 0
+#define SSTAT_CALLED 1
+#define SSTAT_RESPONDED 2
+#define SSTAT_PROGNOTREG 3
+#define SSTAT_RPC 4
+#define SSTAT_RSCRC 5
+#define SSTAT_SYSTEM 6
+
+static char err_usage[] =
+"Usage:\n\typpush [-p <par>] [-d <domainname>] [-h <hostname>] [-v] map\n";
+static char err_bad_args[] =
+ "The %s argument is bad.\n";
+static char err_cant_get_kname[] =
+ "Can't get %s from system call.\n";
+static char err_null_kname[] =
+ "The %s hasn't been set on this machine.\n";
+static char err_bad_domainname[] = "domainname";
+static char err_cant_bind[] =
+ "Can't find a yp server for domain %s. Reason: %s.\n";
+static char err_cant_build_serverlist[] =
+ "Can't build server list from map \"ypservers\". Reason: %s.\n";
+static char err_cant_find_host[] =
+ "Can't find host %s in map \"ypservers\".\n";
+/*
+ * State_duple table. All messages should take 1 arg - the node name.
+ */
+struct state_duple {
+ int state;
+ char *state_msg;
+};
+static struct state_duple state_duples[] = {
+ {SSTAT_INIT, "Internal error trying to talk to %s."},
+ {SSTAT_CALLED, "%s has been called."},
+ {SSTAT_RESPONDED, "%s (v1 ypserv) sent an old-style request."},
+ {SSTAT_PROGNOTREG, "nis server not registered at %s."},
+ {SSTAT_RPC, "RPC error to %s: "},
+ {SSTAT_RSCRC, "Local resource allocation failure - can't talk to %s."},
+ {SSTAT_SYSTEM, "System error talking to %s: "},
+ {0, (char *)NULL}
+};
+/*
+ * Status_duple table. No messages should require any args.
+ */
+static struct status_duple {
+ long status;
+ char *status_msg;
+};
+static struct status_duple status_duples[] = {
+ {YPPUSH_SUCC, "Map successfully transferred."},
+ {YPPUSH_AGE,
+ "Transfer not done: master's version isn't newer."},
+ {YPPUSH_NOMAP, "Failed - ypxfr there can't find a server for map."},
+ {YPPUSH_NODOM, "Failed - domain isn't supported."},
+ {YPPUSH_RSRC, "Failed - local resource allocation failure."},
+ {YPPUSH_RPC, "Failed - ypxfr had an RPC failure"},
+ {YPPUSH_MADDR, "Failed - ypxfr couldn't get the map master's address."},
+ {YPPUSH_YPERR, "Failed - nis server or map format error."},
+ {YPPUSH_BADARGS, "Failed - args to ypxfr were bad."},
+ {YPPUSH_DBM, "Failed - dbm operation on map failed."},
+ {YPPUSH_FILE, "Failed - file I/O operation on map failed"},
+ {YPPUSH_SKEW, "Failed - map version skew during transfer."},
+ {YPPUSH_CLEAR,
+ "Map successfully transferred, but ypxfr \
+ couldn't send \"Clear map\" to ypserv "},
+ {YPPUSH_FORCE,
+ "Failed - no local order number in map - use -f flag to ypxfr."},
+ {YPPUSH_XFRERR, "Failed - ypxfr internal error."},
+ {YPPUSH_REFUSED, "Failed - Transfer request refused."},
+ {YPPUSH_NOALIAS,
+ "Failed - System V domain/map alias not in alias file."},
+ {0, (char *)NULL}
+};
+/*
+ * rpcerr_duple table
+ */
+static struct rpcerr_duple {
+ enum clnt_stat rpc_stat;
+ char *rpc_msg;
+};
+static struct rpcerr_duple rpcerr_duples[] = {
+ {RPC_SUCCESS, "RPC success"},
+ {RPC_CANTENCODEARGS, "RPC Can't encode args"},
+ {RPC_CANTDECODERES, "RPC Can't decode results"},
+ {RPC_CANTSEND, "RPC Can't send"},
+ {RPC_CANTRECV, "RPC Can't recv"},
+ {RPC_TIMEDOUT, "NIS server registered, but does not respond"},
+ {RPC_VERSMISMATCH, "RPC version mismatch"},
+ {RPC_AUTHERROR, "RPC auth error"},
+ {RPC_PROGUNAVAIL, "RPC remote program unavailable"},
+ {RPC_PROGVERSMISMATCH, "RPC program mismatch"},
+ {RPC_PROCUNAVAIL, "RPC unknown procedure"},
+ {RPC_CANTDECODEARGS, "RPC Can't decode args"},
+ {RPC_UNKNOWNHOST, "unknown host"},
+ {RPC_RPCBFAILURE, "rpcbind failure (host is down?)"},
+ {RPC_PROGNOTREGISTERED, "RPC prog not registered"},
+ {RPC_SYSTEMERROR, "RPC system error"},
+ {RPC_SUCCESS, (char *)NULL} /* Duplicate rpc_stat */
+ /* unused in list-end */
+ /* entry */
+};
+
+static void get_default_domain_name(void);
+static void get_command_line_args(int argc, char **argv);
+static unsigned short send_message(struct server *ps,
+ unsigned long program, long *err);
+static void make_server_list(void);
+static void one_host_list(void);
+static void add_server(char *sname, int namelen);
+static int generate_callback(unsigned long *program);
+static void xactid_seed(unsigned long *xactid);
+static void main_loop(unsigned long program);
+static void listener_exit(unsigned long program, int stat);
+static void listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp);
+static void print_state_msg(struct server *s, long e);
+static void print_callback_msg(struct server *s);
+static void rpcerr_msg(enum clnt_stat e);
+static void get_xfr_response(SVCXPRT *transp);
+
+#ifdef SYSVCONFIG
+extern void sysvconfig(void);
+#endif
+extern int yp_getalias(char *key, char *key_alias, int maxlen);
+extern int getdomainname(char *, int);
+
+extern struct rpc_createerr rpc_createerr;
+extern char *sys_errlist[];
+extern int sys_nerr;
+extern CLIENT *__yp_clnt_create_rsvdport();
+
+int
+main(int argc, char **argv)
+{
+ unsigned long program;
+ struct stat sbuf;
+
+ get_command_line_args(argc, argv);
+
+ if (!domain) {
+ get_default_domain_name();
+ }
+
+#ifdef SYSVCONFIG
+ sysvconfig();
+#endif
+
+ if (yp_getalias(domain, domain_alias, NAME_MAX) != 0)
+ fprintf(stderr, "domain alias for %s not found\n", domain);
+ if (yp_getalias(map, map_alias, MAXALIASLEN) != 0)
+ fprintf(stderr, "map alias for %s not found\n", map);
+
+ /* check to see if the map exists in this domain */
+ if (is_yptol_mode())
+ sprintf(ypmapname, "%s/%s/%s%s.dir", ypdbpath, domain_alias,
+ NTOL_PREFIX, map_alias);
+ else
+ sprintf(ypmapname, "%s/%s/%s.dir", ypdbpath, domain_alias,
+ map_alias);
+ if (stat(ypmapname, &sbuf) < 0) {
+ fprintf(stderr, "yppush: Map does not exist.\n");
+ exit(1);
+ }
+
+ if (onehost) {
+ one_host_list();
+ } else {
+ make_server_list();
+ }
+
+ /*
+ * All process exits after the call to generate_callback should be
+ * through listener_exit(program, status), not exit(status), so the
+ * transient server can get unregistered with the portmapper.
+ */
+
+ if (!generate_callback(&program)) {
+ fprintf(stderr, "Can't set up transient callback server.\n");
+ }
+
+ main_loop(program);
+
+ listener_exit(program, 0);
+
+ /* NOTREACHED */
+ return (0);
+}
+
+/*
+ * This does the command line parsing.
+ */
+static void
+get_command_line_args(int argc, char **argv)
+{
+ pusage = err_usage;
+ argv++;
+
+ if (argc < 2) {
+ fprintf(stderr, pusage);
+ exit(1);
+ }
+
+ while (--argc) {
+ if ((*argv)[0] == '-') {
+ switch ((*argv)[1]) {
+ case 'v':
+ verbose = TRUE;
+ argv++;
+ break;
+ case 'd':
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+ argv++;
+ if (((int)strlen(domain)) >
+ YPMAXDOMAIN) {
+ fprintf(stderr,
+ err_bad_args,
+ err_bad_domainname);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, pusage);
+ exit(1);
+ }
+ break;
+ case 'h':
+ if (argc > 1) {
+ onehost = TRUE;
+ argv++;
+ argc--;
+ host = *argv;
+ argv++;
+ } else {
+ fprintf(stderr, pusage);
+ exit(1);
+ }
+ break;
+
+ case 'p':
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ if (sscanf(*argv, "%d", &curpar) != 1) {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+ argv++;
+ if (curpar < 1) {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+ } else {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, pusage);
+ exit(1);
+ }
+ } else {
+ if (!map) {
+ map = *argv;
+ } else {
+ fprintf(stderr, pusage);
+ exit(1);
+ }
+ argv++;
+ }
+ }
+
+ if (!map) {
+ fprintf(stderr, pusage);
+ exit(1);
+ }
+}
+
+/*
+ * This gets the local kernel domainname, and sets the global domain to it.
+ */
+static void
+get_default_domain_name(void)
+{
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ fprintf(stderr, err_cant_get_kname, err_bad_domainname);
+ exit(1);
+ }
+
+ if ((int)strlen(domain) == 0) {
+ fprintf(stderr, err_null_kname, err_bad_domainname);
+ exit(1);
+ }
+}
+
+/*
+ * This verifies that the hostname supplied by the user is in the map
+ * "ypservers" then calls add_server to make it the only entry on the
+ * list of servers.
+ */
+static void
+one_host_list(void)
+{
+ char *key;
+ int keylen;
+ char *val;
+ int vallen;
+ int err;
+ char *ypservers = "ypservers";
+
+ if (verbose) {
+ printf("Verifying YP server: %s\n", host);
+ fflush(stdout);
+ }
+
+ if (err = yp_bind(domain_alias)) {
+ fprintf(stderr, err_cant_bind, domain, yperr_string(err));
+ exit(1);
+ }
+
+ keylen = strlen(host);
+
+ if (yp_match(domain_alias, ypservers, host, keylen,
+ &val, &vallen)) {
+ fprintf(stderr, err_cant_find_host, host);
+ exit(1);
+ }
+
+ add_server(host, keylen);
+}
+
+/*
+ * This uses yp operations to retrieve each server name in the map
+ * "ypservers". add_server is called for each one to add it to the list of
+ * servers.
+ */
+static void
+make_server_list(void)
+{
+ char *key;
+ int keylen;
+ char *outkey;
+ int outkeylen;
+ char *val;
+ int vallen;
+ int err;
+ char *ypservers = "ypservers";
+ int count;
+
+ if (verbose) {
+ printf("Finding YP servers: ");
+ fflush(stdout);
+ count = 4;
+ }
+
+ if (err = yp_bind(domain_alias)) {
+ fprintf(stderr, err_cant_bind, domain, yperr_string(err));
+ exit(1);
+ }
+
+ if (err = yp_first(domain_alias, ypservers, &outkey, &outkeylen,
+ &val, &vallen)) {
+ fprintf(stderr, err_cant_build_serverlist, yperr_string(err));
+ exit(1);
+ }
+
+ for (;;) {
+ add_server(outkey, outkeylen);
+ if (verbose) {
+ printf(" %s", outkey);
+ fflush(stdout);
+ if (count++ == 8) {
+ printf("\n");
+ count = 0;
+ }
+ }
+ free(val);
+ key = outkey;
+ keylen = outkeylen;
+
+ if (err = yp_next(domain_alias, ypservers, key, keylen,
+ &outkey, &outkeylen, &val, &vallen)) {
+
+ if (err == YPERR_NOMORE) {
+ break;
+ } else {
+ fprintf(stderr, err_cant_build_serverlist,
+ yperr_string(err));
+ exit(1);
+ }
+ }
+
+ free(key);
+ }
+ if (count != 0) {
+ if (verbose)
+ printf("\n");
+ }
+}
+
+/*
+ * This adds a single server to the server list.
+ */
+static void
+add_server(char *sname, int namelen)
+{
+ struct server *ps;
+ static unsigned long seq;
+ static unsigned long xactid = 0;
+
+ if (strcmp(sname, my_name) == 0)
+ return;
+
+ if (xactid == 0) {
+ xactid_seed(&xactid);
+ }
+
+ if ((ps = (struct server *)malloc((unsigned)sizeof (struct server)))
+ == (struct server *)NULL) {
+ perror("yppush: malloc failure");
+ exit(1);
+ }
+
+ sname[namelen] = '\0';
+ strcpy(ps->svc_name, sname);
+ ps->state = SSTAT_INIT;
+ ps->status = 0;
+ ps->oldvers = FALSE;
+ ps->xactid = xactid + seq++;
+ ps->pnext = server_list;
+ server_list = ps;
+}
+
+/*
+ * This sets the base range for the transaction ids used in speaking the the
+ * server ypxfr processes.
+ */
+static void
+xactid_seed(unsigned long *xactid)
+{
+ struct timeval t;
+
+ if (gettimeofday(&t) == -1) {
+ perror("yppush gettimeofday failure");
+ *xactid = 1234567;
+ } else {
+ *xactid = t.tv_sec;
+ }
+}
+
+/*
+ * This generates the channel which will be used as the listener process'
+ * service rendezvous point, and comes up with a transient program number
+ * for the use of the RPC messages from the ypxfr processes.
+ */
+static int
+generate_callback(unsigned long *program)
+{
+ unsigned long prognum = 0x40000000, maxprognum;
+ union {
+ unsigned long p;
+ unsigned char b[sizeof (unsigned long)];
+ } u;
+ int ret, i;
+ struct netconfig *nc4, *nc6, *nc;
+ SVCXPRT *trans;
+
+ nc4 = getnetconfigent("udp");
+ nc6 = getnetconfigent("udp6");
+ if (nc4 == 0 && nc6 == 0) {
+ fprintf(stderr,
+ "yppush: Could not get udp or udp6 netconfig entry\n");
+ exit(1);
+ }
+
+ transport4 = (nc4 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc4, 0, 0, 0);
+ transport6 = (nc6 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc6, 0, 0, 0);
+ if (transport4 == 0 && transport6 == 0) {
+ fprintf(stderr, "yppush: Could not create server handle(s)\n");
+ exit(1);
+ }
+
+ /* Find the maximum possible program number using an unsigned long */
+ for (i = 0; i < sizeof (u.b); i++)
+ u.b[i] = 0xff;
+ maxprognum = u.p;
+
+ if (transport4 != 0) {
+ trans = transport4;
+ nc = nc4;
+ } else {
+ trans = transport6;
+ nc = nc6;
+ }
+ while (prognum < maxprognum && (ret =
+ rpcb_set(prognum, YPPUSHVERS, nc, &trans->xp_ltaddr)) == 0)
+ prognum++;
+
+ if (ret == 0) {
+ fprintf(stderr, "yppush: Could not create callback service\n");
+ exit(1);
+ } else {
+ if (trans == transport4 && transport6 != 0) {
+ ret = rpcb_set(prognum, YPPUSHVERS, nc6,
+ &transport6->xp_ltaddr);
+ if (ret == 0) {
+ fprintf(stderr,
+ "yppush: Could not create udp6 callback service\n");
+ exit(1);
+ }
+ }
+ *program = prognum;
+ }
+
+ return (ret);
+}
+
+/*
+ * This is the main loop. Send messages to each server,
+ * and then wait for a response.
+ */
+
+
+add_to_active()
+{
+ struct server *ps;
+ ps = server_list;
+ if (ps == NULL)
+ return (0);
+ server_list = server_list->pnext; /* delete from server_list */
+ ps->pnext = active_list;
+ active_list = ps;
+ return (1);
+}
+
+delete_active(in)
+ struct server *in;
+{
+ struct server *p;
+ struct server *n;
+ if (in == active_list) {
+ active_list = active_list->pnext;
+ return (1);
+ }
+ p = active_list;
+ for (n = active_list; n; n = n->pnext) {
+ if (in == n) {
+ p->pnext = n->pnext;
+ return (0);
+
+ }
+ p = n;
+ }
+ return (-1);
+}
+
+void
+main_loop(program)
+ unsigned long program;
+{
+ pollfd_t *pollset = NULL;
+ int npollfds = 0;
+ int pollret;
+ struct server *ps;
+ long error;
+ int hpar; /* this times par count */
+ int i;
+ int j;
+ int time_now;
+ int docb;
+ int actives = 0;
+ int dead = 0;
+
+ if (grace_period < MIN_GRACE)
+ grace_period = MIN_GRACE;
+ if (transport4 != 0) {
+ if (!svc_reg(transport4, program, YPPUSHVERS,
+ listener_dispatch, 0)) {
+ fprintf(stderr,
+ "Can't set up transient udp callback server.\n");
+ }
+ }
+ if (transport6 != 0) {
+ if (!svc_reg(transport6, program, YPPUSHVERS,
+ listener_dispatch, 0)) {
+ fprintf(stderr,
+ "Can't set up transient udp6 callback server.\n");
+ }
+ }
+ for (;;) {
+ time_now = time(0);
+ if (server_list == NULL) {
+ actives = 0;
+ dead = 0;
+ for (ps = active_list; ps; ps = ps->pnext)
+ if (ps->state == SSTAT_CALLED) {
+ if ((time_now - ps->start_time) <
+ grace_period)
+ actives++;
+ else
+ dead++;
+ }
+ if (actives == 0) {
+ if (verbose) {
+ printf("terminating %d dead\n", dead);
+ fflush(stdout);
+ }
+
+ for (ps = active_list; ps; ps = ps->pnext)
+ if (ps->state == SSTAT_CALLED) {
+ if ((time_now - ps->start_time)
+ >= grace_period) {
+ if (verbose) {
+ printf(
+ "no response from %s -- grace of %d seconds expired.\n",
+ ps->svc_name, grace_period);
+ fflush(stdout);
+ }
+ fprintf(stderr,
+ "No response from ypxfr on %s\n", ps->svc_name);
+ }
+ }
+ break;
+ }
+ }
+ actives = 0;
+ for (ps = active_list; ps; ps = ps->pnext) {
+ if (ps->state == SSTAT_CALLED) {
+ if ((time_now - ps->start_time)
+ < grace_period) {
+ actives++;
+
+ if (verbose) {
+ printf(
+ "No response yet from ypxfr on %s\n", ps->svc_name);
+ fflush(stdout);
+ }
+ }
+ } else {
+ if (verbose) {
+ printf("Deactivating %s\n",
+ ps->svc_name);
+ fflush(stdout);
+ }
+ delete_active(ps);
+ }
+ }
+
+ /* add someone to the active list keep up with curpar */
+ for (i = 0; i < (curpar - actives); i++) {
+ if (add_to_active()) {
+ ps = active_list;
+ ps->state = send_message(ps, program, &error);
+ print_state_msg(ps, error);
+ if (ps->state != SSTAT_CALLED)
+ delete_active(ps); /* zorch it */
+ else
+ ps->start_time = time(0); /* set time */
+ }
+ }
+ docb = 0;
+ for (ps = active_list; ps; ps = ps->pnext)
+ if (ps->state == SSTAT_CALLED) {
+ docb = 1;
+ break;
+ }
+ if (docb == 0) {
+ if (verbose) {
+ printf("No one to wait for this pass.\n");
+ fflush(stdout);
+ }
+ continue; /* try curpar more */
+ }
+
+ if (npollfds != svc_max_pollfd) {
+ pollset = realloc(pollset,
+ sizeof (pollfd_t) * svc_max_pollfd);
+ npollfds = svc_max_pollfd;
+ }
+
+ /*
+ * Get existing array of pollfd's, should really compress
+ * this but it shouldn't get very large (or sparse).
+ */
+ (void) memcpy(pollset, svc_pollfd,
+ sizeof (pollfd_t) * svc_max_pollfd);
+
+ errno = 0;
+ switch (pollret = poll(pollset, npollfds, MIN_GRACE * 1000)) {
+ case -1:
+ if (errno != EINTR) {
+ (void) perror("main loop select");
+ }
+ break;
+
+ case 0:
+ if (verbose) {
+ (void) printf("timeout in main loop select.\n");
+ fflush(stdout);
+ }
+ break;
+
+ default:
+ svc_getreq_poll(pollset, pollret);
+ break;
+ } /* switch */
+ } /* for */
+}
+
+/*
+ * This does the listener process cleanup and process exit.
+ */
+static void
+listener_exit(unsigned long program, int stat)
+{
+ svc_unreg(program, YPPUSHVERS);
+ exit(stat);
+}
+
+/*
+ * This is the listener process' RPC service dispatcher.
+ */
+static void
+listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ switch (rqstp->rq_proc) {
+
+ case YPPUSHPROC_NULL:
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ fprintf(stderr, "Can't reply to rpc call.\n");
+ }
+ break;
+
+ case YPPUSHPROC_XFRRESP:
+ get_xfr_response(transp);
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ break;
+ }
+}
+
+
+/*
+ * This dumps a server state message to stdout. It is called in cases where
+ * we have no expectation of receiving a callback from the remote ypxfr.
+ */
+static void
+print_state_msg(struct server *s, long e)
+{
+ struct state_duple *sd;
+
+ if (s->state == SSTAT_SYSTEM)
+ return; /* already printed */
+
+ if (!verbose && (s->state == SSTAT_RESPONDED ||
+ s->state == SSTAT_CALLED))
+ return;
+
+ for (sd = state_duples; sd->state_msg; sd++) {
+ if (sd->state == s->state) {
+ printf(sd->state_msg, s->svc_name);
+
+ if (s->state == SSTAT_RPC) {
+ rpcerr_msg((enum clnt_stat) e);
+ }
+
+ printf("\n");
+ fflush(stdout);
+ return;
+ }
+ }
+
+ fprintf(stderr, "yppush: Bad server state value %d.\n", s->state);
+}
+
+/*
+ * This dumps a transfer status message to stdout. It is called in
+ * response to a received RPC message from the called ypxfr.
+ */
+static void
+print_callback_msg(struct server *s)
+{
+ register struct status_duple *sd;
+
+ if (!verbose &&
+ (s->status == YPPUSH_AGE) ||
+ (s->status == YPPUSH_SUCC))
+
+ return;
+
+ for (sd = status_duples; sd->status_msg; sd++) {
+
+ if (sd->status == s->status) {
+ printf("Status received from ypxfr on %s:\n\t%s\n",
+ s->svc_name, sd->status_msg);
+ fflush(stdout);
+ return;
+ }
+ }
+
+ fprintf(stderr, "yppush listener: Garbage transaction "
+ "status (value %d) from ypxfr on %s.\n",
+ (int)s->status, s->svc_name);
+}
+
+/*
+ * This dumps an RPC error message to stdout. This is basically a rewrite
+ * of clnt_perrno, but writes to stdout instead of stderr.
+ */
+static void
+rpcerr_msg(enum clnt_stat e)
+{
+ struct rpcerr_duple *rd;
+
+ for (rd = rpcerr_duples; rd->rpc_msg; rd++) {
+
+ if (rd->rpc_stat == e) {
+ printf(rd->rpc_msg);
+ return;
+ }
+ }
+
+ fprintf(stderr, "Bad error code passed to rpcerr_msg: %d.\n", e);
+}
+
+/*
+ * This picks up the response from the ypxfr process which has been started
+ * up on the remote node. The response status must be non-zero, otherwise
+ * the status will be set to "ypxfr error".
+ */
+static void
+get_xfr_response(SVCXPRT *transp)
+{
+ struct yppushresp_xfr resp;
+ register struct server *s;
+
+ if (!svc_getargs(transp, (xdrproc_t)xdr_yppushresp_xfr,
+ (caddr_t)&resp)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ (void) fprintf(stderr, "Can't reply to rpc call.\n");
+ }
+
+ for (s = active_list; s; s = s->pnext) {
+
+ if (s->xactid == resp.transid) {
+ s->status = resp.status ? resp.status: YPPUSH_XFRERR;
+ print_callback_msg(s);
+ s->state = SSTAT_RESPONDED;
+ return;
+ }
+ }
+}
+
+/*
+ * This sends a message to a single ypserv process. The return value is
+ * a state value. If the RPC call fails because of a version
+ * mismatch, we'll assume that we're talking to a version 1 ypserv process,
+ * and will send him an old "YPPROC_GET" request, as was defined in the
+ * earlier version of yp_prot.h
+ */
+static unsigned short
+send_message(struct server *ps, unsigned long program, long *err)
+{
+ struct ypreq_newxfr req;
+ struct ypreq_xfr oldreq;
+ enum clnt_stat s;
+ struct rpc_err rpcerr;
+
+ if ((ps->domb.dom_client = __yp_clnt_create_rsvdport(ps->svc_name,
+ YPPROG, YPVERS,
+ (char *)NULL,
+ 0, 0)) == NULL) {
+
+ if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) {
+ return (SSTAT_PROGNOTREG);
+ } else {
+ printf("Error talking to %s: ", ps->svc_name);
+ rpcerr_msg(rpc_createerr.cf_stat);
+ printf("\n");
+ fflush(stdout);
+ return (SSTAT_SYSTEM);
+ }
+ }
+
+ if (sysinfo(SI_HOSTNAME, my_name, sizeof (my_name)) == -1) {
+ return (SSTAT_RSCRC);
+ }
+
+ if (!oldxfr) {
+ req.ypxfr_domain = domain;
+ req.ypxfr_map = map;
+ req.ypxfr_ordernum = 0;
+ req.ypxfr_owner = my_name;
+ req.name = ps->svc_name;
+ /*
+ * the creation of field req.name, instead of ypreq_xfr (old)
+ * req.port, does not make any sense. it doesn't give any
+ * information to receiving ypserv except its own name !!
+ * new ypserv duplicates work for YPPROC_XFR and YPPROC_NEWXFR
+ */
+ req.transid = ps->xactid;
+ req.proto = program;
+ s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
+ YPPROC_NEWXFR,
+ (xdrproc_t)xdr_ypreq_newxfr,
+ (caddr_t)&req,
+ xdr_void, 0, timeout);
+ }
+
+ clnt_geterr(ps->domb.dom_client, &rpcerr);
+
+ if (s == RPC_PROCUNAVAIL) {
+ oldreq.ypxfr_domain = domain;
+ oldreq.ypxfr_map = map;
+ oldreq.ypxfr_ordernum = 0;
+ oldreq.ypxfr_owner = my_name;
+ oldreq.transid = ps->xactid;
+ oldreq.proto = program;
+ oldreq.port = 0;
+ s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
+ YPPROC_XFR,
+ (xdrproc_t)xdr_ypreq_xfr,
+ (caddr_t)&oldreq,
+ xdr_void, 0, timeout);
+ clnt_geterr(ps->domb.dom_client, &rpcerr);
+ }
+
+ clnt_destroy(ps->domb.dom_client);
+
+ if (s == RPC_SUCCESS) {
+ return (SSTAT_CALLED);
+ } else {
+ *err = (long)rpcerr.re_status;
+ return (SSTAT_RPC);
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * FUNCTION: is_yptol_mode();
+ *
+ * DESCRIPTION: Determines if we should run in N2L or traditional mode based
+ * on the presence of the N2L mapping file.
+ *
+ * This is a copy of a function from libnisdb. If more than this
+ * one function become required it may be worth linking the
+ * entire lib.
+ *
+ * INPUTS: Nothing
+ *
+ * OUTPUTS: TRUE = Run in N2L mode
+ * FALSE = Run in traditional mode.
+ */
+bool_t
+is_yptol_mode()
+{
+ struct stat filestat;
+
+ if (stat(NTOL_MAP_FILE, &filestat) != -1)
+ return (TRUE);
+
+ return (FALSE);
+}
diff --git a/usr/src/cmd/ypcmd/ypserv.c b/usr/src/cmd/ypcmd/ypserv.c
new file mode 100644
index 0000000000..6e1eaa6797
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv.c
@@ -0,0 +1,643 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This contains the mainline code for the YP server. Data
+ * structures which are process-global are also in this module.
+ */
+
+/* this is so that ypserv will compile under 5.5 */
+#define _SVID_GETTOD
+#include <sys/time.h>
+extern int gettimeofday(struct timeval *);
+
+#include "ypsym.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <rpc/rpc.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <sys/select.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <signal.h>
+#include "shim.h"
+#include "yptol.h"
+#include <syslog.h>
+
+static char register_failed[] = "ypserv: Unable to register service for ";
+bool silent = TRUE;
+
+/*
+ * client_setup_failure will be TRUE, if setup of the
+ * connection to rpc.nisd_resolv failed
+ */
+bool client_setup_failure = FALSE;
+
+/* N2L options */
+bool init_dit = FALSE;
+bool init_containers = FALSE;
+bool init_maps = FALSE;
+char **ldapCLA = NULL;
+
+/* For DNS forwarding command line option (-d) */
+bool dnsforward = FALSE;
+int resolv_pid = 0;
+CLIENT *resolv_client = NULL;
+char *resolv_tp = "ticots";
+
+#ifdef MINUS_C_OPTION
+/* For cluster support (-c) */
+bool multiflag = FALSE;
+#endif
+
+static char logfile[] = "/var/yp/ypserv.log";
+void logprintf(char *format, ...);
+
+static void ypexit(void);
+static void ypinit(int argc, char **argv);
+static void ypdispatch(struct svc_req *rqstp, SVCXPRT *transp);
+static void ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp);
+static void ypget_command_line_args(int argc, char **argv);
+extern void setup_resolv(bool *fwding, int *child,
+ CLIENT **client, char *tp_type, long prognum);
+static void cleanup_resolv(int);
+
+/*
+ * This is the main line code for the yp server.
+ */
+int
+main(int argc, char **argv)
+{
+ if (geteuid() != 0) {
+ fprintf(stderr, "must be root to run %s\n", argv[0]);
+ exit(1);
+ }
+
+ /* Set up shop */
+ ypinit(argc, argv);
+
+ /* If requested set up the N2L maps. May take a while */
+ if (init_dit)
+ if (FAILURE == dump_maps_to_dit(init_containers)) {
+ fprintf(stderr, "Fatal error dumping maps to DIT."
+ " See syslog and LDAP server logs for details.\n");
+ exit(1);
+ }
+
+ if (init_maps)
+ if (FAILURE == dump_dit_to_maps()) {
+ fprintf(stderr, "Fatal error dumping DIT to maps."
+ " See syslog and LDAP server logs for details.\n");
+ exit(1);
+ }
+
+ /*
+ * If we were asked to init the maps now exit. User will then use
+ * ypstart to restart ypserv and all the other NIS daemons.
+ */
+ if (init_dit || init_maps) {
+ printf("Map setup complete. Please now restart NIS daemons "
+ "with ypstart.\n");
+ exit(0);
+ }
+
+ svc_run();
+
+ /*
+ * This is stupid, but the compiler likes to warn us about the
+ * absence of returns from main()
+ */
+ return (0);
+}
+
+typedef struct {
+ char *netid;
+ int fd;
+ int olddispatch; /* Register on protocol version 1 ? */
+ int class; /* Other services that must succeed */
+ SVCXPRT *xprt;
+ int ok; /* Registered successfully ? */
+} ypservice_t;
+
+ypservice_t service[] = {
+ { "udp", -1, 1, 4, 0, 0 },
+ { "tcp", -1, 1, 4, 0, 0 },
+ { "udp6", -1, 0, 6, 0, 0 },
+ { "tcp6", -1, 0, 6, 0, 0 }
+};
+
+#define MAXSERVICES (sizeof (service)/sizeof (service[0]))
+
+int service_classes[MAXSERVICES];
+
+/*
+ * Does startup processing for the yp server.
+ */
+static void
+ypinit(int argc, char **argv)
+{
+ int pid;
+ int stat, t;
+ struct sigaction act;
+ int ufd, tfd;
+ SVCXPRT *utransp, *ttransp;
+ struct netconfig *nconf;
+ int connmaxrec = RPC_MAXDATASIZE;
+ int i, j, services = 0;
+
+
+ /*
+ * Init yptol flags. Will get redone by init_lock_system() but we need
+ * to know if we should parse yptol cmd line options.
+ */
+ init_yptol_flag();
+
+ ypget_command_line_args(argc, argv);
+
+ if (silent) {
+ pid = (int)fork();
+
+ if (pid == -1) {
+ logprintf("ypserv: ypinit fork failure.\n");
+ ypexit();
+ }
+
+ if (pid != 0) {
+ exit(0);
+ }
+ }
+
+ if (!init_lock_system(FALSE)) {
+ ypexit();
+ }
+
+ get_secure_nets(argv[0]);
+
+ if (silent) {
+ closelog();
+ closefrom(3);
+ }
+
+ if (yptol_mode) {
+ stat = parseConfig(ldapCLA, NTOL_MAP_FILE);
+ if (stat == 1) {
+ logprintf("NIS to LDAP mapping inactive.\n");
+ } else if (stat != 0) {
+ logprintf("Aborting after NIS to LDAP mapping "
+ "error.\n");
+ fflush(stderr);
+ exit(-1);
+ }
+ }
+
+ if (silent) {
+ freopen("/dev/null", "r", stdin);
+ if (access(logfile, _IOWRT)) {
+ freopen("/dev/null", "w", stdout);
+ freopen("/dev/null", "w", stderr);
+ } else {
+ freopen(logfile, "a", stdout);
+ freopen(logfile, "a", stderr);
+ }
+
+ t = open("/dev/tty", 2);
+
+ setpgrp();
+ }
+
+#ifdef SYSVCONFIG
+ sigset(SIGHUP, (void (*)())sysvconfig);
+#else
+ sigset(SIGHUP, SIG_IGN);
+#endif
+
+ /*
+ * Setting disposition to SIG_IGN will not create zombies when child
+ * processes terminate.
+ */
+ sigset(SIGCHLD, SIG_IGN);
+
+ act.sa_handler = cleanup_resolv;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESETHAND;
+ sigaction(SIGTERM, &act, (struct sigaction *)NULL);
+ sigaction(SIGQUIT, &act, (struct sigaction *)NULL);
+ sigaction(SIGABRT, &act, (struct sigaction *)NULL);
+ sigaction(SIGBUS, &act, (struct sigaction *)NULL);
+ sigaction(SIGSEGV, &act, (struct sigaction *)NULL);
+
+ /*
+ * Set non-blocking mode and maximum record size for
+ * connection oriented RPC transports.
+ */
+ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
+ logprintf("unable to set maximum RPC record size");
+ }
+
+ svc_unreg(YPPROG, YPVERS);
+ svc_unreg(YPPROG, YPVERS_ORIG);
+
+ for (i = 0; i < sizeof (service)/sizeof (ypservice_t); i++) {
+
+ service_classes[i] = -1;
+
+ if ((nconf = getnetconfigent(service[i].netid)) == NULL) {
+ logprintf("getnetconfigent(\"%s\") failed\n",
+ service[i].netid);
+ continue;
+ }
+
+ if ((service[i].fd = t_open(nconf->nc_device, O_RDWR, NULL)) <
+ 0) {
+ logprintf("t_open failed for %s\n", service[i].netid);
+ freenetconfigent(nconf);
+ continue;
+ }
+
+ if (netdir_options(nconf, ND_SET_RESERVEDPORT, service[i].fd,
+ NULL) < 0) {
+ logprintf("could not set reserved port for %s\n",
+ service[i].netid);
+ (void) close(service[i].fd);
+ service[i].fd = -1;
+ freenetconfigent(nconf);
+ continue;
+ }
+
+ if ((service[i].xprt = svc_tli_create(service[i].fd, nconf,
+ NULL, 0, 0)) == NULL) {
+ logprintf("svc_tli_create failed for %s\n",
+ service[i].netid);
+ (void) close(service[i].fd);
+ service[i].fd = -1;
+ freenetconfigent(nconf);
+ continue;
+ }
+
+ if (!svc_reg(service[i].xprt, YPPROG, YPVERS, ypdispatch,
+ nconf)) {
+ logprintf("%s %s\n", service[i].netid, register_failed);
+ svc_destroy(service[i].xprt);
+ service[i].xprt = 0;
+ (void) close(service[i].fd);
+ service[i].fd = -1;
+ freenetconfigent(nconf);
+ continue;
+ }
+
+ if (service[i].olddispatch && !svc_reg(service[i].xprt, YPPROG,
+ YPVERS_ORIG, ypolddispatch, nconf)) {
+ logprintf("old %s %s\n",
+ service[i].netid, register_failed);
+ /* Can only unregister prognum/versnum */
+ svc_destroy(service[i].xprt);
+ service[i].xprt = 0;
+ (void) close(service[i].fd);
+ service[i].fd = -1;
+ freenetconfigent(nconf);
+ continue;
+ }
+
+ services++;
+ service[i].ok = 1;
+ service_classes[i] = service[i].class;
+
+ freenetconfigent(nconf);
+
+ }
+
+ /*
+ * Check if we managed to register enough services to continue.
+ * It's OK if we managed to register all IPv4 services but no
+ * IPv6, or the other way around, but not if we (say) registered
+ * IPv4 UDP but not TCP.
+ */
+ if (services > 0) {
+ for (j = 0; j < MAXSERVICES; j++) {
+ if (service_classes[j] >= 0) {
+ /*
+ * Must have all services of this class
+ * registered.
+ */
+ for (i = 0; i < MAXSERVICES; i++) {
+ if (service[i].ok == 0 &&
+ service[i].class ==
+ service_classes[j]) {
+ logprintf(
+ "unable to register all services for class %d\n",
+ service[i].class);
+ ypexit();
+ }
+ }
+ }
+ }
+ } else {
+ logprintf("unable to register any services\n");
+ ypexit();
+ }
+
+ /* Now we setup circuit_n or yp_all() and yp_update() will not work */
+ if (!svc_create(ypdispatch, YPPROG, YPVERS, "circuit_n")) {
+ logprintf("circuit_n %s\n", register_failed);
+ ypexit();
+ }
+
+ if (dnsforward) {
+ setup_resolv(&dnsforward, &resolv_pid,
+ &resolv_client, resolv_tp, 0);
+ if (resolv_client == NULL)
+ client_setup_failure = TRUE;
+ }
+}
+
+void
+cleanup_resolv(int sig)
+{
+ if (resolv_pid)
+ kill(resolv_pid, sig);
+
+ kill(getpid(), sig);
+}
+
+/*
+ * This picks up any command line args passed from the process invocation.
+ */
+static void
+ypget_command_line_args(int argc, char **argv)
+{
+ for (argv++; --argc; argv++) {
+
+ if ((*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+#ifdef MINUS_C_OPTION
+ case 'c':
+ multiflag = TRUE;
+ break;
+#endif
+ case 'd':
+ if (access("/etc/resolv.conf", F_OK) == -1) {
+ fprintf(stderr,
+ "No /etc/resolv.conf file, -d option ignored\n");
+ } else {
+ dnsforward = TRUE;
+ }
+ break;
+ case 'I':
+ init_containers = TRUE;
+ /* ... and also do -i stuff */
+ case 'i':
+ if (yptol_mode) {
+ init_dit = TRUE;
+ } else {
+ fprintf(stderr, "-%c option is illegal "
+ "if not in NIS to LDAP mode. Exiting\n",
+ (*argv)[1]);
+ fflush(stderr);
+ exit(-1);
+ }
+
+ /* Handle -ir */
+ if ('r' != (*argv)[2])
+ break;
+
+ case 'r':
+ if (yptol_mode) {
+ init_maps = TRUE;
+ } else {
+ fprintf(stderr, "-r option is illegal "
+ "if not in NIS to LDAP mode. "
+ "Exiting\n");
+ fflush(stderr);
+ exit(-1);
+ }
+ break;
+ case 'v':
+ silent = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* If setting up don't run silent or demonize */
+ if (init_dit || init_maps)
+ silent = FALSE;
+
+}
+
+/*
+ * This dispatches to server action routines based on the input procedure
+ * number. ypdispatch is called from the RPC function svc_run.
+ */
+static void
+ypdispatch(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ sigset_t set, oset;
+
+
+#ifdef SYSVCONFIG
+ /* prepare to answer questions about system v filesystem aliases */
+ sysvconfig();
+#endif
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set, &oset);
+
+ switch (rqstp->rq_proc) {
+
+ case YPPROC_NULL:
+
+ if (!svc_sendreply(transp, xdr_void, 0))
+ logprintf("ypserv: Can't reply to rpc call.\n");
+ break;
+
+ case YPPROC_DOMAIN:
+ ypdomain(transp, TRUE);
+ break;
+
+ case YPPROC_DOMAIN_NONACK:
+ ypdomain(transp, FALSE);
+ break;
+
+ case YPPROC_MATCH:
+ ypmatch(transp, rqstp);
+ break;
+
+ case YPPROC_FIRST:
+ ypfirst(transp);
+ break;
+
+ case YPPROC_NEXT:
+ ypnext(transp);
+ break;
+
+ case YPPROC_XFR:
+ ypxfr(transp, YPPROC_XFR);
+ break;
+
+ case YPPROC_NEWXFR:
+ ypxfr(transp, YPPROC_NEWXFR);
+ break;
+
+ case YPPROC_CLEAR:
+ ypclr_current_map();
+
+ if (!svc_sendreply(transp, xdr_void, 0))
+ logprintf("ypserv: Can't reply to rpc call.\n");
+ break;
+
+ case YPPROC_ALL:
+ ypall(transp);
+ break;
+
+ case YPPROC_MASTER:
+ ypmaster(transp);
+ break;
+
+ case YPPROC_ORDER:
+ yporder(transp);
+ break;
+
+ case YPPROC_MAPLIST:
+ ypmaplist(transp);
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ break;
+
+ }
+
+ sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
+
+}
+
+static void
+ypolddispatch(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ sigset_t set, oset;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set, &oset);
+
+ switch (rqstp->rq_proc) {
+
+ case YPOLDPROC_NULL:
+ if (!svc_sendreply(transp, xdr_void, 0))
+ logprintf("ypserv: Can't replay to rpc call.\n");
+ break;
+
+ case YPOLDPROC_DOMAIN:
+ ypdomain(transp, TRUE);
+ break;
+
+ case YPOLDPROC_DOMAIN_NONACK:
+ ypdomain(transp, FALSE);
+ break;
+
+ case YPOLDPROC_MATCH:
+ ypoldmatch(transp, rqstp);
+ break;
+
+ case YPOLDPROC_FIRST:
+ ypoldfirst(transp);
+ break;
+
+ case YPOLDPROC_NEXT:
+ ypoldnext(transp);
+ break;
+
+ case YPOLDPROC_POLL:
+ ypoldpoll(transp);
+ break;
+
+ case YPOLDPROC_PUSH:
+ ypoldpush(transp);
+ break;
+
+ case YPOLDPROC_PULL:
+ ypoldpull(transp);
+ break;
+
+ case YPOLDPROC_GET:
+ ypoldget(transp);
+
+ default:
+ svcerr_noproc(transp);
+ break;
+ }
+
+ sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
+}
+
+/*
+ * This flushes output to stderr, then aborts the server process to leave a
+ * core dump.
+ */
+static void
+ypexit(void)
+{
+ fflush(stderr);
+ abort();
+}
+
+/*
+ * This constructs a logging record.
+ */
+void
+logprintf(char *format, ...)
+{
+ va_list ap;
+ struct timeval t;
+
+ va_start(ap, format);
+
+ if (silent) {
+ gettimeofday(&t);
+ fseek(stderr, 0, 2);
+ fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec));
+ }
+
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fflush(stderr);
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_ancil.c b/usr/src/cmd/ypcmd/ypserv_ancil.c
new file mode 100644
index 0000000000..6f172ccdf9
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_ancil.c
@@ -0,0 +1,184 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)ypserv_ancil.c 1.13 88/02/08 Copyr 1984 Sun Micro";
+#endif
+
+#include <dirent.h>
+#include <syslog.h>
+#include "ypsym.h"
+#include "ypdefs.h"
+USE_YPDBPATH
+USE_DBM
+#include "shim_hooks.h"
+#include "shim.h"
+#include "yptol.h"
+
+extern unsigned int strlen();
+extern int strcmp();
+extern int isvar_sysv();
+extern char *strncpy();
+extern int yp_getkey();
+
+/*
+ * This generates a list of the maps in a domain.
+ */
+int
+yplist_maps(domain, list)
+ char *domain;
+ struct ypmaplist **list;
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char domdir[MAXNAMLEN + 1];
+ char path[MAXNAMLEN + 1];
+ char map_key[YPMAXMAP + 1];
+ int error;
+ char *ext;
+ struct ypmaplist *map;
+ int namesz;
+ char *mapname;
+
+ *list = (struct ypmaplist *)NULL;
+
+ if (!ypcheck_domain(domain)) {
+ return (YP_NODOM);
+ }
+
+ (void) strcpy(domdir, ypdbpath);
+ (void) strcat(domdir, "/");
+ (void) strcat(domdir, domain);
+
+ if ((dirp = opendir(domdir)) == NULL) {
+ return (YP_YPERR);
+ }
+
+ error = YP_TRUE;
+
+ for (dp = readdir(dirp); error == YP_TRUE && dp != NULL;
+ dp = readdir(dirp)) {
+ /*
+ * If it's possible that the file name is one of the two files
+ * implementing a map, remove the extension (dbm_pag or dbm_dir)
+ */
+ namesz = (int)strlen(dp->d_name);
+
+ if (namesz < sizeof (dbm_pag) - 1)
+ continue; /* Too Short */
+
+ ext = &(dp->d_name[namesz - (sizeof (dbm_pag) - 1)]);
+
+ if (strcmp(ext, dbm_pag) != 0)
+ continue; /* No dbm file extension */
+
+ *ext = '\0';
+
+
+ /*
+ * In yptol mode look at LDAP_ prefixed maps. In non yptol mode
+ * ignore them.
+ */
+ if (yptol_mode) {
+ if (0 != strncmp(dp->d_name, NTOL_PREFIX,
+ strlen(NTOL_PREFIX)))
+ continue;
+
+ /*
+ * Already have an LDAP_ prefix. Don't want to add it
+ * twice.
+ */
+ mapname = dp->d_name + strlen(NTOL_PREFIX);
+ } else {
+ if (0 == strncmp(dp->d_name, NTOL_PREFIX,
+ strlen(NTOL_PREFIX)))
+ continue;
+ mapname = dp->d_name;
+ }
+
+ ypmkfilename(domain, mapname, path);
+
+ /*
+ * At this point, path holds the map file base name (no dbm
+ * file extension), and mapname holds the map name.
+ */
+ if (ypcheck_map_existence(path) &&
+ !onmaplist(mapname, *list)) {
+
+ if ((map = (struct ypmaplist *)malloc(
+ sizeof (struct ypmaplist))) == NULL) {
+ error = YP_YPERR;
+ break;
+ }
+
+ map->ypml_next = *list;
+ *list = map;
+ namesz = (int)strlen(mapname);
+
+ if (namesz <= YPMAXMAP) {
+ if (yp_getkey(mapname, map_key,
+ MAXALIASLEN) < 0) {
+
+ fprintf(stderr,
+ "yplist_maps: getkey failed for %s\n",
+ mapname);
+ error = YP_YPERR;
+ break;
+ } else
+ (void) strcpy(map->ypml_name, map_key);
+ } else {
+ if (yp_getkey(mapname, map_key,
+ MAXALIASLEN) < 0) {
+ fprintf(stderr,
+ "yplist_maps: getkey failed for %s\n",
+ mapname);
+ error = YP_YPERR;
+ break;
+ } else if (strcmp(mapname, map_key) == 0) {
+ (void) strncpy(map->ypml_name,
+ mapname,
+ (unsigned int) namesz);
+ map->ypml_name[YPMAXMAP] = '\0';
+ } else {
+ (void) strcpy(map->ypml_name, map_key);
+ }
+ }
+ }
+ }
+
+ closedir(dirp);
+ return (error);
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_map.c b/usr/src/cmd/ypcmd/ypserv_map.c
new file mode 100644
index 0000000000..455d8db192
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_map.c
@@ -0,0 +1,263 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <malloc.h>
+#include "ypsym.h"
+#include "ypdefs.h"
+
+/* Use N2L version of DBM calls */
+#include "shim_hooks.h"
+
+USE_YP_MASTER_NAME
+USE_YP_LAST_MODIFIED
+USE_YPDBPATH
+USE_YP_SECURE
+USE_DBM
+
+#include <ctype.h>
+
+static DBM *cur_fdb; /* will be passwd back up by ypset_current_map */
+static enum { UNKNOWN, SECURE, PUBLIC } current_map_access = UNKNOWN;
+static char map_owner[MAX_MASTER_NAME + 1];
+
+extern unsigned int ypcheck_domain();
+int check_secure_net_ti(struct netbuf *caller, char *ypname);
+
+/*
+ * The retrieves the order number of a named map from the order number datum
+ * in the map data base.
+ */
+bool
+ypget_map_order(char *map, char *domain, uint_t *order)
+{
+ datum key;
+ datum val;
+ char toconvert[MAX_ASCII_ORDER_NUMBER_LENGTH + 1];
+ uint_t error;
+ DBM *fdb;
+
+ if ((fdb = ypset_current_map(map, domain, &error)) != NULL) {
+ key.dptr = yp_last_modified;
+ key.dsize = yp_last_modified_sz;
+ val = dbm_fetch(fdb, key);
+
+ if (val.dptr != (char *)NULL) {
+
+ if (val.dsize > MAX_ASCII_ORDER_NUMBER_LENGTH) {
+ return (FALSE);
+ }
+
+ /*
+ * This is getting recopied here because val.dptr
+ * points to static memory owned by the dbm package,
+ * and we have no idea whether numeric characters
+ * follow the order number characters, nor whether
+ * the mess is null-terminated at all.
+ */
+
+ memcpy(toconvert, val.dptr, val.dsize);
+ toconvert[val.dsize] = '\0';
+ *order = (unsigned long) atol(toconvert);
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+
+ } else {
+ return (FALSE);
+ }
+}
+
+/*
+ * The retrieves the master server name of a named map from the master datum
+ * in the map data base.
+ */
+bool
+ypget_map_master(char **owner, DBM *fdb)
+{
+ datum key;
+ datum val;
+
+ key.dptr = yp_master_name;
+ key.dsize = yp_master_name_sz;
+ val = dbm_fetch(fdb, key);
+
+ if (val.dptr != (char *)NULL) {
+
+ if (val.dsize > MAX_MASTER_NAME) {
+ return (FALSE);
+ }
+
+ /*
+ * This is getting recopied here because val.dptr
+ * points to static memory owned by the dbm package.
+ */
+ memcpy(map_owner, val.dptr, val.dsize);
+ map_owner[val.dsize] = '\0';
+ *owner = map_owner;
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+/*
+ * This makes a map into the current map, and calls dbminit on that map
+ * and returns the DBM pointer to the map. Procedures called by
+ * ypserv dispatch routine would use this pointer for successive
+ * ndbm operations. Returns an YP_xxxx error code in error if FALSE.
+ */
+DBM *
+ypset_current_map(char *map, char *domain, uint_t *error)
+{
+ char mapname[MAXNAMLEN + 1];
+ int lenm, lend;
+
+ /* Do not allow any path as a domain name or a map name. */
+ if (!map || ((lenm = (int)strlen(map)) == 0) || (lenm > YPMAXMAP) ||
+ !domain || ((lend = (int)strlen(domain)) == 0) ||
+ (lend > YPMAXDOMAIN) || (strchr(map, '/') != NULL) ||
+ (strchr(domain, '/') != NULL)) {
+ *error = YP_BADARGS;
+ return (FALSE);
+ }
+
+ if (FALSE == ypmkfilename(domain, map, mapname))
+ return (FALSE);
+
+ if ((cur_fdb) && (strcmp(mapname, get_map_name(cur_fdb)) == 0)) {
+ return (cur_fdb);
+ }
+
+ /* If there was a previous open map close it */
+ if (NULL != cur_fdb)
+ dbm_close(cur_fdb);
+
+ /* Set the map access as "unknown" as the new map has not been loaded */
+ current_map_access = UNKNOWN;
+
+ /* All the map locking is now handled inside the dbm_open shim */
+ if ((cur_fdb = dbm_open(mapname, O_RDWR, 0644)) != NULL) {
+ return (cur_fdb);
+ }
+
+ if (ypcheck_domain(domain)) {
+
+ if (ypcheck_map_existence(mapname)) {
+ *error = YP_BADDB;
+ } else {
+ *error = YP_NOMAP;
+ }
+
+ } else {
+ *error = YP_NODOM;
+ }
+
+ return (NULL);
+}
+
+/*
+ * This checks to see if there is a current map, and, if there is, does a
+ * dbmclose on it and sets the current map name and its DBM ptr to null.
+ */
+void
+ypclr_current_map(void)
+{
+ if (cur_fdb != NULL) {
+ (void) dbm_close(cur_fdb);
+ cur_fdb = NULL;
+ }
+ current_map_access = UNKNOWN;
+}
+
+/*
+ * Checks to see if caller has permission to query the current map (as
+ * set by ypset_current_map()). Returns TRUE if access is granted and
+ * FALSE otherwise. If FALSE then sets *error to YP_xxxxxxxx.
+ */
+bool
+yp_map_access(SVCXPRT *transp, uint_t *error, DBM *fdb)
+{
+ char *ypname = "ypserv";
+ struct netbuf *nbuf;
+ sa_family_t af;
+ in_port_t port;
+
+ nbuf = svc_getrpccaller(transp);
+ af = ((struct sockaddr_storage *)nbuf->buf)->ss_family;
+ if (af != AF_INET && af != AF_INET6)
+ return (FALSE);
+
+ if (!(check_secure_net_ti(nbuf, ypname))) {
+ *error = YP_NOMAP;
+ return (FALSE);
+ }
+
+ /* XXX - I expect that this won't happen much */
+ if (current_map_access == PUBLIC) {
+ return (TRUE);
+ }
+
+ if (af == AF_INET6) {
+ port = ntohs(((struct sockaddr_in6 *)nbuf->buf)->sin6_port);
+ } else {
+ port = ntohs(((struct sockaddr_in *)nbuf->buf)->sin_port);
+ }
+ if (port < IPPORT_RESERVED) {
+ return (TRUE);
+ }
+
+ if (current_map_access == UNKNOWN) {
+ datum key;
+ datum val;
+
+ key.dptr = yp_secure;
+ key.dsize = yp_secure_sz;
+ val = dbm_fetch(fdb, key);
+ if (val.dptr == (char *)NULL) {
+ current_map_access = PUBLIC;
+ return (TRUE);
+ }
+ current_map_access = SECURE;
+ }
+
+ /* current_map_access == SECURE and non-priviledged caller */
+ *error = YP_NOMAP;
+ return (FALSE);
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_net_secure.c b/usr/src/cmd/ypcmd/ypserv_net_secure.c
new file mode 100644
index 0000000000..2b51faaa24
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_net_secure.c
@@ -0,0 +1,230 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <syslog.h>
+#include <sys/tiuser.h>
+
+#define ACCFILE "/var/yp/securenets"
+#define MAXLINE 128
+
+typedef union {
+ struct in_addr in4;
+ struct in6_addr in6;
+} inaddr_t;
+
+struct seclist {
+ sa_family_t af;
+ inaddr_t mask;
+ inaddr_t net;
+ struct seclist *next;
+};
+
+static int string2inaddr(char *, sa_family_t *, inaddr_t *);
+static int addrequal(sa_family_t af, inaddr_t *laddr, inaddr_t *mask,
+ inaddr_t *caddr);
+
+static struct seclist *slist;
+static int nofile = 0;
+
+void
+get_secure_nets(char *daemon_name)
+{
+ FILE *fp;
+ char strung[MAXLINE], nmask[MAXLINE], net[MAXLINE];
+ inaddr_t maskin, netin;
+ sa_family_t maskaf, netaf;
+ struct seclist *tmp1, *tmp2;
+ int items = 0, line = 0;
+ if (fp = fopen(ACCFILE, "r")) {
+ tmp1 = (struct seclist *) malloc(sizeof (struct seclist));
+ slist = tmp2 = tmp1;
+ while (fgets(strung, MAXLINE, fp)) {
+ line++;
+ if (strung[strlen(strung) - 1] != '\n') {
+ syslog(LOG_ERR|LOG_DAEMON,
+ "%s: %s line %d: too long\n",
+ daemon_name, ACCFILE, line);
+ exit(1);
+ }
+ if (strung[0] != '#') {
+ items++;
+ if (sscanf(strung,
+ "%46s%46s", nmask, net) < 2) {
+
+ syslog(LOG_ERR|LOG_DAEMON,
+ "%s: %s line %d: missing fields\n",
+ daemon_name, ACCFILE, line);
+ exit(1);
+ }
+ netaf = AF_UNSPEC;
+ if (! string2inaddr(net, &netaf, &netin)) {
+ syslog(LOG_ERR|LOG_DAEMON,
+ "%s: %s line %d: error in address\n",
+ daemon_name, ACCFILE, line);
+ exit(1);
+ }
+ maskaf = netaf;
+ if (! string2inaddr(nmask, &maskaf, &maskin) ||
+ maskaf != netaf) {
+ syslog(LOG_ERR|LOG_DAEMON,
+ "%s: %s line %d: error in netmask\n",
+ daemon_name, ACCFILE, line);
+ exit(1);
+ }
+ if (! addrequal(netaf, &netin, &maskin,
+ &netin)) {
+ syslog(LOG_ERR|LOG_DAEMON,
+ "%s: %s line %d: netmask does not match network\n",
+ daemon_name, ACCFILE, line);
+ exit(1);
+ }
+
+ tmp1->af = netaf;
+ tmp1->mask = maskin;
+ tmp1->net = netin;
+ tmp1->next = (struct seclist *)
+ malloc(sizeof (struct seclist));
+ tmp2 = tmp1;
+ tmp1 = tmp1->next;
+ }
+ }
+ tmp2->next = NULL;
+ /* if nothing to process, set nofile flag and free up memory */
+ if (items == 0) {
+ free(slist);
+ nofile = 1;
+ }
+ } else {
+ syslog(LOG_WARNING|LOG_DAEMON, "%s: no %s file\n",
+ daemon_name, ACCFILE);
+ nofile = 1;
+ }
+}
+
+int
+check_secure_net_ti(struct netbuf *caller, char *ypname) {
+ struct seclist *tmp;
+ sa_family_t af;
+ inaddr_t addr;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (nofile)
+ return (1);
+
+ af = ((struct sockaddr_storage *)caller->buf)->ss_family;
+ if (af == AF_INET) {
+ addr.in4 = ((struct sockaddr_in *)caller->buf)->sin_addr;
+ } else if (af == AF_INET6) {
+ addr.in6 = ((struct sockaddr_in6 *)caller->buf)->sin6_addr;
+ } else {
+ return (1);
+ }
+
+ tmp = slist;
+ while (tmp != NULL) {
+ if (af == tmp->af &&
+ addrequal(af, &tmp->net, &tmp->mask, &addr)) {
+ return (1);
+ }
+ tmp = tmp->next;
+ }
+ syslog(LOG_ERR|LOG_DAEMON, "%s: access denied for %s\n",
+ ypname, inet_ntop(af,
+ (af == AF_INET6) ? (void *)&addr.in6 :
+ (void *)&addr.in4, buf, sizeof (buf)));
+
+ return (0);
+}
+
+
+static int
+string2inaddr(char *string, sa_family_t *af, inaddr_t *addr) {
+
+ sa_family_t stringaf = AF_UNSPEC;
+
+ stringaf = (strchr(string, ':') != 0) ? AF_INET6 : AF_INET;
+
+ if (*af != AF_UNSPEC && strcmp(string, "host") == 0) {
+ if (*af == AF_INET) {
+ string = "255.255.255.255";
+ stringaf = AF_INET;
+ } else if (*af == AF_INET6) {
+ string = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
+ stringaf = AF_INET6;
+ }
+ }
+
+ *af = stringaf;
+ if (inet_pton(*af, string, (*af == AF_INET6) ? (void *)&addr->in6 :
+ (void *)&addr->in4) != 1) {
+ return (0);
+ }
+
+ return (1);
+}
+
+
+static int
+addrequal(sa_family_t af, inaddr_t *laddr, inaddr_t *mask, inaddr_t *caddr) {
+
+ if (af == AF_INET6) {
+ int i;
+ for (i = 0; i < sizeof (laddr->in6.s6_addr); i++) {
+ if ((caddr->in6.s6_addr[i] & mask->in6.s6_addr[i]) !=
+ laddr->in6.s6_addr[i])
+ return (0);
+ }
+ return (1);
+ } else if (af == AF_INET) {
+ return ((caddr->in4.s_addr & mask->in4.s_addr) ==
+ laddr->in4.s_addr);
+ } else {
+ return (0);
+ }
+}
+
+
+static void
+print_inaddr(char *string, sa_family_t af, inaddr_t *addr) {
+
+ char buf[INET6_ADDRSTRLEN];
+
+ printf("%s %s %s\n",
+ string, (af == AF_INET6)?"AF_INET6":"AF_INET",
+ inet_ntop(af, (af == AF_INET6) ? (void *)&addr->in6 :
+ (void *)&addr->in4, buf, sizeof (buf)));
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_proc.c b/usr/src/cmd/ypcmd/ypserv_proc.c
new file mode 100644
index 0000000000..c5e8bc7c16
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_proc.c
@@ -0,0 +1,1521 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * This contains YP server code which supplies the set of functions
+ * requested using rpc. The top level functions in this module
+ * are those which have symbols of the form YPPROC_xxxx defined in
+ * yp_prot.h, and symbols of the form YPOLDPROC_xxxx defined in ypsym.h.
+ * The latter exist to provide compatibility to the old version of the yp
+ * protocol/server, and may emulate the behavior of the previous software
+ * by invoking some other program.
+ *
+ * This module also contains functions which are used by (and only by) the
+ * top-level functions here.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/systeminfo.h>
+#include <rpc/rpc.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "ypsym.h"
+#include "ypdefs.h"
+#include <ctype.h>
+
+/* Use shim version of DBM calls */
+#include "shim.h"
+#include "shim_hooks.h"
+
+USE_YP_PREFIX
+USE_YP_SECURE
+USE_YP_INTERDOMAIN
+
+#ifndef YPXFR_PROC
+#define YPXFR_PROC "/usr/lib/netsvc/yp/ypxfr"
+#endif
+static char ypxfr_proc[] = YPXFR_PROC;
+#ifndef YPPUSH_PROC
+#define YPPUSH_PROC "/usr/lib/netsvc/yp/yppush"
+#endif
+static char yppush_proc[] = YPPUSH_PROC;
+struct yppriv_sym {
+ char *sym;
+ unsigned len;
+};
+static char err_fork[] = "ypserv: %s fork failure.\n";
+#define FORK_ERR logprintf(err_fork, fun)
+static char err_execl[] = "ypserv: %s execl failure.\n";
+#define EXEC_ERR logprintf(err_execl, fun)
+static char err_respond[] = "ypserv: %s can't respond to rpc request.\n";
+#define RESPOND_ERR logprintf(err_respond, fun)
+static char err_free[] = "ypserv: %s can't free args.\n";
+#define FREE_ERR logprintf(err_free, fun)
+static char err_map[] = "ypserv: %s no such map or access denied.\n";
+#define MAP_ERR logprintf(err_map, fun)
+static char err_vers[] = "ypserv: %s version not supported.\n";
+#define VERS_ERR logprintf(err_vers, fun)
+
+static void ypfilter(DBM *fdb, datum *inkey, datum *outkey, datum *val,
+ uint_t *status, bool_t update);
+static bool isypsym(datum *key);
+static bool xdrypserv_ypall(XDR *xdrs, struct ypreq_nokey *req);
+static int multihomed(struct ypreq_key req, struct ypresp_val *resp,
+ SVCXPRT *xprt, DBM *fdb);
+static int omultihomed(struct yprequest req, struct ypresponse *resp,
+ SVCXPRT *xprt, DBM *fdb);
+
+
+/* For DNS forwarding */
+extern bool dnsforward;
+extern bool client_setup_failure;
+extern int resolv_pid;
+extern CLIENT *resolv_client;
+extern char *resolv_tp;
+
+/*
+ * This determines whether or not a passed domain is served by this
+ * server, and returns a boolean. Used by both old and new protocol
+ * versions.
+ */
+void
+ypdomain(SVCXPRT *transp, bool always_respond)
+{
+ char domain_name[YPMAXDOMAIN + 1];
+ char *pdomain_name = domain_name;
+ bool isserved;
+ char *fun = "ypdomain";
+ struct netbuf *nbuf;
+ sa_family_t af;
+
+ memset(domain_name, 0, sizeof (domain_name));
+
+ if (!svc_getargs(transp, (xdrproc_t)xdr_ypdomain_wrap_string,
+ (caddr_t)&pdomain_name)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ /*
+ * If the file /var/yp/securenets is present on the server, and if
+ * the hostname is present in the file, then let the client bind to
+ * the server.
+ */
+ nbuf = svc_getrpccaller(transp);
+ af = ((struct sockaddr_storage *)nbuf->buf)->ss_family;
+ if (af != AF_INET && af != AF_INET6) {
+ logprintf("Protocol incorrect\n");
+ return;
+ }
+
+ if (!(check_secure_net_ti(nbuf, fun))) {
+ MAP_ERR;
+ return;
+ }
+
+ isserved = ypcheck_domain(domain_name);
+
+ if (isserved || always_respond) {
+
+ if (!svc_sendreply(transp, xdr_bool, (char *)&isserved)) {
+ RESPOND_ERR;
+ }
+ if (!isserved)
+ logprintf("Domain %s not supported\n",
+ domain_name);
+
+ } else {
+ /*
+ * This case is the one in which the domain is not
+ * supported, and in which we are not to respond in the
+ * unsupported case. We are going to make an error happen
+ * to allow the portmapper to end his wait without the
+ * normal timeout period. The assumption here is that
+ * the only process in the world which is using the function
+ * in its no-answer-if-nack form is the portmapper, which is
+ * doing the krock for pseudo-broadcast. If some poor fool
+ * calls this function as a single-cast message, the nack
+ * case will look like an incomprehensible error. Sigh...
+ * (The traditional Unix disclaimer)
+ */
+
+ svcerr_decode(transp);
+ logprintf("Domain %s not supported (broadcast)\n",
+ domain_name);
+ }
+}
+
+/*
+ * This implements the yp "match" function.
+ */
+void
+ypmatch(SVCXPRT *transp, struct svc_req *rqstp)
+{
+ struct ypreq_key req;
+ struct ypresp_val resp;
+ char *fun = "ypmatch";
+ DBM *fdb;
+
+ memset(&req, 0, sizeof (req));
+ memset(&resp, 0, sizeof (resp));
+ resp.status = (unsigned)YP_NOKEY;
+
+ if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ /*
+ * sanity check the map name and to a DBM lookup
+ * also perform an access check...
+ */
+ if ((fdb = ypset_current_map(req.map, req.domain,
+ &resp.status)) != NULL &&
+ yp_map_access(transp, &resp.status, fdb)) {
+
+ /* Check with the DBM database */
+ resp.valdat = dbm_fetch(fdb, req.keydat);
+ if (resp.valdat.dptr != NULL) {
+ resp.status = YP_TRUE;
+ if (!silent)
+ printf("%s: dbm: %40.40s\n",
+ fun, resp.valdat.dptr);
+ goto send_reply;
+ }
+
+ /*
+ * If we're being asked to match YP_SECURE or YP_INTERDOMAIN
+ * and we haven't found it in the dbm file, then we don't
+ * really want to waste any more time. Specifically, we don't
+ * want to ask DNS
+ */
+ if (req.keydat.dsize == 0 ||
+ req.keydat.dptr == NULL ||
+ req.keydat.dptr[0] == '\0' ||
+ strncmp(req.keydat.dptr, yp_secure, req.keydat.dsize) == 0 ||
+ strncmp(req.keydat.dptr, yp_interdomain, req.keydat.dsize) == 0) {
+ goto send_reply;
+ }
+
+ /* Let's try the YP_MULTI_ hack... */
+#ifdef MINUS_C_OPTION
+ if (multiflag == TRUE && multihomed(req, &resp, transp, fdb))
+ goto send_reply;
+#else
+ if (multihomed(req, &resp, transp, fdb))
+ goto send_reply;
+#endif
+
+ /*
+ * Let's try DNS, but if client_setup_failure is set,
+ * we have tried DNS in the past and failed, there is
+ * no reason in forcing an infinite loop by turning
+ * off DNS in setup_resolv() only to turn it back on
+ * again here.
+ */
+ if (!dnsforward && !client_setup_failure) {
+ datum idkey, idval;
+ idkey.dptr = yp_interdomain;
+ idkey.dsize = yp_interdomain_sz;
+ idval = dbm_fetch(fdb, idkey);
+ if (idval.dptr)
+ dnsforward = TRUE;
+ }
+
+ if (dnsforward) {
+ if (!resolv_pid || !resolv_client) {
+ setup_resolv(&dnsforward, &resolv_pid,
+ &resolv_client, resolv_tp, 0);
+ if (resolv_client == NULL)
+ client_setup_failure = TRUE;
+ }
+
+ if (resolv_req(&dnsforward, &resolv_client,
+ &resolv_pid, resolv_tp,
+ rqstp->rq_xprt, &req,
+ req.map) == TRUE)
+ goto free_args;
+ }
+ }
+ send_reply:
+
+ if (!svc_sendreply(transp, (xdrproc_t)xdr_ypresp_val,
+ (caddr_t)&resp)) {
+ RESPOND_ERR;
+ }
+
+ free_args:
+
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_key,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+}
+
+
+/*
+ * This implements the yp "get first" function.
+ */
+void
+ypfirst(SVCXPRT *transp)
+{
+ struct ypreq_nokey req;
+ struct ypresp_key_val resp;
+ char *fun = "ypfirst";
+ DBM *fdb;
+
+ memset(&req, 0, sizeof (req));
+ memset(&resp, 0, sizeof (resp));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if ((fdb = ypset_current_map(req.map, req.domain,
+ &resp.status)) != NULL &&
+ yp_map_access(transp, &resp.status, fdb)) {
+ ypfilter(fdb, NULL,
+ &resp.keydat, &resp.valdat, &resp.status, FALSE);
+ }
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdr_ypresp_key_val,
+ (char *)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+}
+
+/*
+ * This implements the yp "get next" function.
+ */
+void
+ypnext(SVCXPRT *transp)
+{
+ struct ypreq_key req;
+ struct ypresp_key_val resp;
+ char *fun = "ypnext";
+ DBM *fdb;
+
+ memset(&req, 0, sizeof (req));
+ memset(&resp, 0, sizeof (resp));
+
+ if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if ((fdb = ypset_current_map(req.map, req.domain,
+ &resp.status)) != NULL &&
+ yp_map_access(transp, &resp.status, fdb)) {
+ ypfilter(fdb, &req.keydat,
+ &resp.keydat, &resp.valdat, &resp.status, FALSE);
+ }
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdr_ypresp_key_val,
+ (char *)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)xdr_ypreq_key,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+}
+
+/*
+ * This implements the "transfer map" function. It takes the domain
+ * and map names and the callback information provided by the
+ * requester (yppush on some node), and execs a ypxfr process to do
+ * the actual transfer.
+ */
+void
+ypxfr(SVCXPRT *transp, int prog)
+{
+ struct ypreq_newxfr newreq;
+ struct ypreq_xfr oldreq;
+ struct ypresp_val resp; /* not returned to the caller */
+ char transid[32];
+ char proto[32];
+ char name[256];
+ char *pdomain, *pmap;
+ pid_t pid = -1;
+ char *fun = "ypxfr";
+ DBM *fdb;
+
+ if (prog == YPPROC_NEWXFR) {
+ memset(&newreq, 0, sizeof (newreq));
+ if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_newxfr,
+ (char *)&newreq)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+#ifdef OPCOM_DEBUG
+ fprintf(stderr, "newreq:\n"
+ "\tmap_parms:\n"
+ "\t\tdomain: %s\n"
+ "\t\tmap: %s\n"
+ "\t\tordernum: %u\n"
+ "\t\towner: %s\n"
+ "\ttransid: %u\n"
+ "\tproto: %u\n"
+ "\tname: %s\n\n",
+ newreq.map_parms.domain,
+ newreq.map_parms.map,
+ newreq.map_parms.ordernum,
+ newreq.map_parms.owner,
+ newreq.transid,
+ newreq.proto,
+ newreq.name);
+#endif
+ sprintf(transid, "%u", newreq.transid);
+ sprintf(proto, "%u", newreq.proto);
+ sprintf(name, "%s", newreq.ypxfr_owner);
+ pdomain = newreq.ypxfr_domain;
+ pmap = newreq.ypxfr_map;
+ } else if (prog == YPPROC_XFR) {
+ memset(&oldreq, 0, sizeof (oldreq));
+ if (!svc_getargs(transp,
+ (xdrproc_t)xdr_ypreq_xfr,
+ (char *)&oldreq)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+#ifdef OPCOM_DEBUG
+ fprintf(stderr, "oldreq:\n"
+ "\tmap_parms:\n"
+ "\t\tdomain: %s\n"
+ "\t\tmap: %s\n"
+ "\t\tordernum: %u\n"
+ "\t\towner: %s\n"
+ "\ttransid: %u\n"
+ "\tproto: %u\n"
+ "\tport: %u\n\n",
+ oldreq.map_parms.domain,
+ oldreq.map_parms.map,
+ oldreq.map_parms.ordernum,
+ oldreq.map_parms.owner,
+ oldreq.transid,
+ oldreq.proto,
+ oldreq.port);
+#endif
+
+ sprintf(transid, "%u", oldreq.transid);
+ sprintf(proto, "%u", oldreq.proto);
+ sprintf(name, "%s", oldreq.ypxfr_owner);
+ pdomain = oldreq.ypxfr_domain;
+ pmap = oldreq.ypxfr_map;
+ } else {
+ VERS_ERR;
+ }
+
+ /* Check that the map exists and is accessible */
+ if ((fdb = ypset_current_map(pmap, pdomain, &resp.status)) != NULL &&
+ yp_map_access(transp, &resp.status, fdb)) {
+
+ pid = vfork();
+ if (pid == -1) {
+ FORK_ERR;
+ } else if (pid == 0) {
+ if (prog == YPPROC_NEWXFR || prog == YPPROC_XFR) {
+#ifdef OPCOM_DEBUG
+ fprintf(stderr,
+ "EXECL: %s, -d, %s, -C, %s, %s, %s, %s\n",
+ ypxfr_proc, pdomain,
+ transid, proto, name, pmap);
+#endif
+ if (execl(ypxfr_proc, "ypxfr", "-d",
+ pdomain, "-C", transid, proto,
+ name, pmap, NULL))
+ EXEC_ERR;
+ } else {
+ VERS_ERR;
+ }
+ _exit(1);
+ }
+
+ } else {
+ MAP_ERR;
+ }
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ RESPOND_ERR;
+ }
+
+ if (prog == YPPROC_NEWXFR) {
+ if (!svc_freeargs(transp,
+ (xdrproc_t)xdr_ypreq_newxfr,
+ (char *)&newreq)) {
+ FREE_ERR;
+ }
+ }
+}
+
+/*
+ * This implements the "get all" function.
+ */
+void
+ypall(SVCXPRT *transp)
+{
+ struct ypreq_nokey req;
+ struct ypresp_val resp; /* not returned to the caller */
+ pid_t pid;
+ char *fun = "ypall";
+ DBM *fdb;
+
+ req.domain = req.map = NULL;
+
+ memset((char *)&req, 0, sizeof (req));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ pid = fork1();
+
+ if (pid) {
+
+ if (pid == -1) {
+ FORK_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+
+ return;
+ }
+
+ /*
+ * access control hack: If denied then invalidate the map name.
+ */
+ ypclr_current_map();
+ if ((fdb = ypset_current_map(req.map,
+ req.domain, &resp.status)) != NULL &&
+ !yp_map_access(transp, &resp.status, fdb)) {
+
+ req.map[0] = '-';
+ }
+
+ /*
+ * This is the child process. The work gets done by xdrypserv_ypall/
+ * we must clear the "current map" first so that we do not
+ * share a seek pointer with the parent server.
+ */
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdrypserv_ypall,
+ (char *)&req)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+
+ /*
+ * In yptol mode we may start a cache update thread within a child
+ * process. It is thus important that child processes do not exit,
+ * killing any such threads, before the thread has completed.
+ */
+ if (yptol_mode) {
+ thr_join(0, NULL, NULL);
+ }
+
+ exit(0);
+}
+
+/*
+ * This implements the "get master name" function.
+ */
+void
+ypmaster(SVCXPRT *transp)
+{
+ struct ypreq_nokey req;
+ struct ypresp_master resp;
+ char *nullstring = "";
+ char *fun = "ypmaster";
+ DBM *fdb;
+
+ memset((char *)&req, 0, sizeof (req));
+ resp.master = nullstring;
+ resp.status = YP_TRUE;
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if ((fdb = ypset_current_map(req.map,
+ req.domain, &resp.status)) != NULL &&
+ yp_map_access(transp, &resp.status, fdb)) {
+
+ if (!ypget_map_master(&resp.master, fdb)) {
+ resp.status = (unsigned)YP_BADDB;
+ }
+ }
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdr_ypresp_master,
+ (char *)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+}
+
+/*
+ * This implements the "get order number" function.
+ */
+void
+yporder(SVCXPRT *transp)
+{
+ struct ypreq_nokey req;
+ struct ypresp_order resp;
+ char *fun = "yporder";
+ DBM *fdb;
+
+ req.domain = req.map = NULL;
+ resp.status = YP_TRUE;
+ resp.ordernum = 0;
+
+ memset((char *)&req, 0, sizeof (req));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ resp.ordernum = 0;
+
+ if ((fdb = ypset_current_map(req.map,
+ req.domain,
+ &resp.status)) != NULL &&
+ yp_map_access(transp, &resp.status, fdb)) {
+
+ if (!ypget_map_order(req.map, req.domain, &resp.ordernum)) {
+ resp.status = (unsigned)YP_BADDB;
+ }
+ }
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdr_ypresp_order,
+ (char *)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+}
+
+void
+ypmaplist(SVCXPRT *transp)
+{
+ char domain_name[YPMAXDOMAIN + 1];
+ char *pdomain = domain_name;
+ char *fun = "ypmaplist";
+ struct ypresp_maplist maplist;
+ struct ypmaplist *tmp;
+
+ maplist.list = (struct ypmaplist *)NULL;
+
+ memset(domain_name, 0, sizeof (domain_name));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)xdr_ypdomain_wrap_string,
+ (caddr_t)&pdomain)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ maplist.status = yplist_maps(domain_name, &maplist.list);
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdr_ypresp_maplist,
+ (char *)&maplist)) {
+ RESPOND_ERR;
+ }
+
+ while (maplist.list) {
+ tmp = maplist.list->ypml_next;
+ free((char *)maplist.list);
+ maplist.list = tmp;
+ }
+}
+
+/*
+ * Ancillary functions used by the top-level functions within this
+ * module
+ */
+
+/*
+ * This returns TRUE if a given key is a yp-private symbol, otherwise
+ * FALSE
+ */
+static bool
+isypsym(datum *key)
+{
+ if ((key->dptr == NULL) ||
+ (key->dsize < yp_prefix_sz) ||
+ memcmp(yp_prefix, key->dptr, yp_prefix_sz) ||
+ (!memcmp(key->dptr, "YP_MULTI_", 9))) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * This provides private-symbol filtration for the enumeration functions.
+ */
+static void
+ypfilter(DBM *fdb, datum *inkey, datum *outkey, datum *val, uint_t *status,
+ bool_t update)
+{
+ datum k;
+
+ if (inkey) {
+
+ if (isypsym(inkey)) {
+ *status = (unsigned)YP_BADARGS;
+ return;
+ }
+
+ k = dbm_do_nextkey(fdb, *inkey);
+ } else {
+ k = dbm_firstkey(fdb);
+ }
+
+ while (k.dptr && isypsym(&k)) {
+ k = dbm_nextkey(fdb);
+ }
+
+ if (k.dptr == NULL) {
+ *status = YP_NOMORE;
+ return;
+ }
+
+ *outkey = k;
+
+ /*
+ * In N2L mode we must call a version of dbm_fetch() that either does
+ * or does not check for entry updates. In non N2L mode both of these
+ * will end up doing a normal dbm_fetch().
+ */
+ if (update)
+ *val = shim_dbm_fetch(fdb, k);
+ else
+ *val = shim_dbm_fetch_noupdate(fdb, k);
+
+ if (val->dptr != NULL) {
+ *status = YP_TRUE;
+ } else {
+ *status = (unsigned)YP_BADDB;
+ }
+}
+
+/*
+ * Serializes a stream of struct ypresp_key_val's. This is used
+ * only by the ypserv side of the transaction.
+ */
+static bool
+xdrypserv_ypall(XDR *xdrs, struct ypreq_nokey *req)
+{
+ bool_t more = TRUE;
+ struct ypresp_key_val resp;
+ DBM *fdb;
+
+ resp.keydat.dptr = resp.valdat.dptr = (char *)NULL;
+ resp.keydat.dsize = resp.valdat.dsize = 0;
+
+ if ((fdb = ypset_current_map(req->map, req->domain,
+ &resp.status)) != NULL) {
+ ypfilter(fdb, (datum *) NULL, &resp.keydat, &resp.valdat,
+ &resp.status, FALSE);
+
+ while (resp.status == YP_TRUE) {
+ if (!xdr_bool(xdrs, &more)) {
+ return (FALSE);
+ }
+
+ if (!xdr_ypresp_key_val(xdrs, &resp)) {
+ return (FALSE);
+ }
+
+ ypfilter(fdb, &resp.keydat, &resp.keydat, &resp.valdat,
+ &resp.status, FALSE);
+ }
+ }
+
+ if (!xdr_bool(xdrs, &more)) {
+ return (FALSE);
+ }
+
+ if (!xdr_ypresp_key_val(xdrs, &resp)) {
+ return (FALSE);
+ }
+
+ more = FALSE;
+
+ if (!xdr_bool(xdrs, &more)) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Additions for sparc cluster support
+ */
+
+/*
+ * Check for special multihomed host cookie in the key. If there,
+ * collect the addresses from the comma separated list and return
+ * the one that's nearest the client.
+ */
+static int
+multihomed(struct ypreq_key req, struct ypresp_val *resp,
+ SVCXPRT *xprt, DBM *fdb)
+{
+ char *cp, *bp;
+ ulong_t bestaddr, call_addr;
+ struct netbuf *nbuf;
+ char name[PATH_MAX];
+ static char localbuf[_PBLKSIZ]; /* buffer for multihomed IPv6 addr */
+
+ if (strcmp(req.map, "hosts.byname") &&
+ strcmp(req.map, "ipnodes.byname"))
+ /* default status is YP_NOKEY */
+ return (0);
+
+ if (strncmp(req.keydat.dptr, "YP_MULTI_", 9)) {
+ datum tmpname;
+
+ strncpy(name, "YP_MULTI_", 9);
+ strncpy(name + 9, req.keydat.dptr, req.keydat.dsize);
+ tmpname.dsize = req.keydat.dsize + 9;
+ tmpname.dptr = name;
+ resp->valdat = dbm_fetch(fdb, tmpname);
+ } else {
+ /*
+ * Return whole line (for debugging) if YP_MULTI_hostnam
+ * is specified.
+ */
+ resp->valdat = dbm_fetch(fdb, req.keydat);
+ if (resp->valdat.dptr != NULL)
+ return (1);
+ }
+
+ if (resp->valdat.dptr == NULL)
+ return (0);
+
+ strncpy(name, req.keydat.dptr, req.keydat.dsize);
+ name[req.keydat.dsize] = NULL;
+
+ if (strcmp(req.map, "ipnodes.byname") == 0) {
+ /*
+ * This section handles multihomed IPv6 addresses.
+ * It returns all the IPv6 addresses one per line and only
+ * the requested hostname is returned. NO aliases will be
+ * returned. This is done exactly the same way DNS forwarding
+ * daemon handles multihomed hosts.
+ * New IPv6 enabled clients should be able to handle this
+ * information returned. The sorting is also the client's
+ * responsibility.
+ */
+
+ char *buf, *endbuf;
+
+ if ((buf = strdup(resp->valdat.dptr)) == NULL) /* no memory */
+ return (0);
+ if ((bp = strtok(buf, " \t")) == NULL) { /* no address field */
+ free(buf);
+ return (0);
+ }
+ if ((cp = strtok(NULL, "")) == NULL) { /* no host field */
+ free(buf);
+ return (0);
+ }
+ if ((cp = strtok(bp, ",")) != NULL) { /* multihomed host */
+ int bsize;
+
+ localbuf[0] = '\0';
+ bsize = sizeof (localbuf);
+ endbuf = localbuf;
+
+ while (cp) {
+ if ((strlen(cp) + strlen(name)) >= bsize) {
+ /* out of range */
+ break;
+ }
+ sprintf(endbuf, "%s %s\n", cp, name);
+ cp = strtok(NULL, ",");
+ endbuf = &endbuf[strlen(endbuf)];
+ bsize = &localbuf[sizeof (localbuf)] - endbuf;
+ }
+ resp->valdat.dptr = localbuf;
+ resp->valdat.dsize = strlen(localbuf);
+ }
+
+ free(buf);
+ /* remove trailing newline */
+ if (resp->valdat.dsize &&
+ resp->valdat.dptr[resp->valdat.dsize-1] == '\n') {
+ resp->valdat.dptr[resp->valdat.dsize-1] = '\0';
+ resp->valdat.dsize -= 1;
+ }
+
+ resp->status = YP_TRUE;
+ return (1);
+ }
+ nbuf = svc_getrpccaller(xprt);
+ /*
+ * OK, now I have a netbuf structure which I'm supposed to
+ * treat as opaque... I hate transport independance!
+ * So, we're just gonna doit wrong... By wrong I mean that
+ * we assume that the buf part of the netbuf structure is going
+ * to be a sockaddr_in. We'll then check the assumed family
+ * member and hope that we find AF_INET in there... if not
+ * then we can't continue.
+ */
+ if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET)
+ return (0);
+
+ call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr;
+
+ cp = resp->valdat.dptr;
+ if ((bp = strtok(cp, " \t")) == NULL) /* no address field */
+ return (0);
+ if ((cp = strtok(NULL, "")) == NULL) /* no host field */
+ return (0);
+ bp = strtok(bp, ",");
+
+ bestaddr = inet_addr(bp);
+ while (cp = strtok(NULL, ",")) {
+ ulong_t taddr;
+
+ taddr = inet_addr(cp);
+ if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr))
+ bestaddr = taddr;
+ }
+ cp = resp->valdat.dptr;
+ sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name);
+ resp->valdat.dsize = strlen(cp);
+
+ resp->status = YP_TRUE;
+
+ return (1);
+}
+
+/* V1 dispatch routines */
+void
+ypoldmatch(SVCXPRT *transp, struct svc_req *rqstp)
+{
+ bool dbmop_ok = TRUE;
+ struct yprequest req;
+ struct ypreq_key nrq;
+ struct ypresponse resp;
+ char *fun = "ypoldmatch";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+ memset((void *) &resp, 0, sizeof (resp));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (req.yp_reqtype != YPMATCH_REQTYPE) {
+ resp.ypmatch_resp_status = (unsigned)YP_BADARGS;
+ dbmop_ok = FALSE;
+ }
+
+ if (dbmop_ok &&
+ (((fdb = ypset_current_map(req.ypmatch_req_map,
+ req.ypmatch_req_domain,
+ &resp.ypmatch_resp_status))
+ != NULL) &&
+ yp_map_access(transp,
+ &resp.ypmatch_resp_status,
+ fdb))) {
+
+ /* Check with the DBM database */
+ resp.ypmatch_resp_valdat = dbm_fetch(fdb,
+ req.ypmatch_req_keydat);
+
+ if (resp.ypmatch_resp_valptr != NULL) {
+ resp.ypmatch_resp_status = YP_TRUE;
+ if (!silent)
+ printf("%s: dbm: %s\n",
+ fun, resp.ypmatch_resp_valptr);
+ goto send_oldreply;
+ }
+
+ /*
+ * If we're being asked to match YP_SECURE or YP_INTERDOMAIN
+ * and we haven't found it in the dbm file, then we don't
+ * really want to waste any more time. Specifically, we don't
+ * want to ask DNS
+ */
+ if (req.ypmatch_req_keysize == 0 ||
+ req.ypmatch_req_keyptr == NULL ||
+ req.ypmatch_req_keyptr[0] == '\0' ||
+ strncmp(req.ypmatch_req_keyptr, "YP_SECURE", 9) == 0 ||
+ strncmp(req.ypmatch_req_keyptr, "YP_INTERDOMAIN", 14) == 0)
+
+ goto send_oldreply;
+
+ /* Let's try the YP_MULTI_ hack... */
+#ifdef MINUS_C_OPTION
+ if (multiflag == TRUE && omultihomed(req, &resp, transp, fdb))
+ goto send_oldreply;
+#else
+ if (omultihomed(req, &resp, transp, fdb))
+ goto send_oldreply;
+#endif
+
+ /* Let's try DNS */
+ if (!dnsforward) {
+ USE_YP_INTERDOMAIN
+ datum idkey, idval;
+ idkey.dptr = yp_interdomain;
+ idkey.dsize = yp_interdomain_sz;
+ idval = dbm_fetch(fdb, idkey);
+ if (idval.dptr)
+ dnsforward = TRUE;
+ }
+
+ if (dnsforward) {
+ if (!resolv_pid)
+ setup_resolv(&dnsforward, &resolv_pid, &resolv_client,
+ resolv_tp, 0);
+
+ if (req.yp_reqtype == YPREQ_KEY) {
+ nrq = req.yp_reqbody.yp_req_keytype;
+
+ resolv_req(&dnsforward, &resolv_client, &resolv_pid,
+ resolv_tp, rqstp->rq_xprt,
+ &nrq, nrq.map);
+ }
+ return;
+ }
+ }
+
+ send_oldreply:
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)_xdr_ypresponse,
+ (caddr_t)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (char *)&req)) {
+ FREE_ERR;
+ }
+}
+
+void
+ypoldfirst(SVCXPRT *transp)
+{
+ bool dbmop_ok = TRUE;
+ struct yprequest req;
+ struct ypresponse resp;
+ char *fun = "ypoldfirst";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+ memset((void *) &resp, 0, sizeof (resp));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (req.yp_reqtype != YPFIRST_REQTYPE) {
+ resp.ypfirst_resp_status = (unsigned)YP_BADARGS;
+ dbmop_ok = FALSE;
+ }
+
+ if (dbmop_ok &&
+ ((fdb = ypset_current_map(req.ypfirst_req_map,
+ req.ypfirst_req_domain,
+ &resp.ypfirst_resp_status))
+ != NULL) &&
+ yp_map_access(transp,
+ &resp.ypfirst_resp_status,
+ fdb)) {
+
+ resp.ypfirst_resp_keydat = dbm_firstkey(fdb);
+
+ if (resp.ypfirst_resp_keyptr != NULL) {
+ resp.ypfirst_resp_valdat =
+ dbm_fetch(fdb, resp.ypfirst_resp_keydat);
+
+ if (resp.ypfirst_resp_valptr != NULL) {
+ resp.ypfirst_resp_status = YP_TRUE;
+ } else {
+ resp.ypfirst_resp_status = (unsigned)YP_BADDB;
+ }
+ } else {
+ resp.ypfirst_resp_status = (unsigned)YP_NOKEY;
+ }
+ }
+
+ resp.yp_resptype = YPFIRST_RESPTYPE;
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)_xdr_ypresponse,
+ (caddr_t)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ FREE_ERR;
+ }
+}
+
+void
+ypoldnext(SVCXPRT *transp)
+{
+ bool dbmop_ok = TRUE;
+ struct yprequest req;
+ struct ypresponse resp;
+ char *fun = "ypoldnext";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+ memset((void *) &resp, 0, sizeof (resp));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (req.yp_reqtype != YPNEXT_REQTYPE) {
+ resp.ypnext_resp_status = (unsigned)YP_BADARGS;
+ dbmop_ok = FALSE;
+ }
+
+ if (dbmop_ok &&
+ ((fdb = ypset_current_map(req.ypnext_req_map,
+ req.ypnext_req_domain,
+ &resp.ypnext_resp_status)) != NULL &&
+ yp_map_access(transp, &resp.ypnext_resp_status, fdb))) {
+
+ resp.ypnext_resp_keydat = dbm_nextkey(fdb);
+
+ if (resp.ypnext_resp_keyptr != NULL) {
+ resp.ypnext_resp_valdat =
+ dbm_fetch(fdb, resp.ypnext_resp_keydat);
+
+ if (resp.ypnext_resp_valptr != NULL) {
+ resp.ypnext_resp_status = YP_TRUE;
+ } else {
+ resp.ypnext_resp_status = (unsigned)YP_BADDB;
+ }
+ } else {
+ resp.ypnext_resp_status = (unsigned)YP_NOMORE;
+ }
+ }
+
+ resp.yp_resptype = YPNEXT_RESPTYPE;
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)_xdr_ypresponse,
+ (caddr_t)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ FREE_ERR;
+ }
+}
+
+/*
+ * This retrieves the order number and master peer name from the map.
+ * The conditions for the various message fields are: domain is filled
+ * in iff the domain exists. map is filled in iff the map exists.
+ * order number is filled in iff it's in the map. owner is filled in
+ * iff the master peer is in the map.
+ */
+void
+ypoldpoll(SVCXPRT *transp)
+{
+ struct yprequest req;
+ struct ypresponse resp;
+ char *map = "";
+ char *domain = "";
+ char *owner = "";
+ uint_t error;
+ char *fun = "ypoldpoll";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+ memset((void *) &resp, 0, sizeof (resp));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (req.yp_reqtype == YPPOLL_REQTYPE) {
+ if (strcmp(req.yppoll_req_domain, "yp_private") == 0 ||
+ strcmp(req.yppoll_req_map, "ypdomains") == 0 ||
+ strcmp(req.yppoll_req_map, "ypmaps") == 0) {
+
+ /*
+ * Backward comatibility for 2.0 NIS servers
+ */
+ domain = req.yppoll_req_domain;
+ map = req.yppoll_req_map;
+ } else if ((fdb = ypset_current_map(req.yppoll_req_map,
+ req.yppoll_req_domain,
+ &error)) != NULL) {
+ domain = req.yppoll_req_domain;
+ map = req.yppoll_req_map;
+ ypget_map_order(map, domain,
+ &resp.yppoll_resp_ordernum);
+ ypget_map_master(&owner, fdb);
+ } else {
+ switch ((int)error) {
+ case YP_BADDB:
+ map = req.yppoll_req_map;
+ /* Fall through to set the domain too. */
+
+ case YP_NOMAP:
+ domain = req.yppoll_req_domain;
+ break;
+ }
+ }
+ }
+
+ resp.yp_resptype = YPPOLL_RESPTYPE;
+ resp.yppoll_resp_domain = domain;
+ resp.yppoll_resp_map = map;
+ resp.yppoll_resp_owner = owner;
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)_xdr_ypresponse,
+ (caddr_t)&resp)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ FREE_ERR;
+ }
+}
+
+void
+ypoldpush(SVCXPRT *transp)
+{
+ struct yprequest req;
+ struct ypresp_val resp;
+ pid_t pid = -1;
+ char *fun = "ypoldpush";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (((fdb = ypset_current_map(req.yppush_req_map,
+ req.yppush_req_domain,
+ &resp.status)) != NULL) &&
+ (yp_map_access(transp, &resp.status, fdb))) {
+
+ pid = vfork();
+ }
+
+ if (pid == -1) {
+ FORK_ERR;
+ } else if (pid == 0) {
+ ypclr_current_map();
+
+ if (execl(yppush_proc, "yppush", "-d", req.yppush_req_domain,
+ req.yppush_req_map, NULL)) {
+ EXEC_ERR;
+ }
+ _exit(1);
+ }
+
+ if (!svc_sendreply(transp,
+ (xdrproc_t)xdr_void,
+ (caddr_t)NULL)) {
+ RESPOND_ERR;
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ FREE_ERR;
+ }
+}
+
+void
+ypoldpull(SVCXPRT *transp)
+{
+ struct yprequest req;
+ struct ypresp_val resp;
+ pid_t pid = -1;
+ char *fun = "ypoldpull";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (req.yp_reqtype == YPPULL_REQTYPE) {
+
+ if (((fdb = ypset_current_map(req.yppull_req_map,
+ req.yppull_req_domain,
+ &resp.status)) == NULL) ||
+ (yp_map_access(transp, &resp.status, fdb))) {
+ pid = vfork();
+ }
+
+ if (pid == -1) {
+ FORK_ERR;
+ } else if (pid == 0) {
+ ypclr_current_map();
+
+ if (execl(ypxfr_proc, "ypxfr", "-d",
+ req.yppull_req_domain,
+ req.yppull_req_map, NULL)) {
+ EXEC_ERR;
+ }
+ _exit(1);
+ }
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ FREE_ERR;
+ }
+}
+
+void
+ypoldget(SVCXPRT *transp)
+{
+ struct yprequest req;
+ struct ypresp_val resp;
+ pid_t pid = -1;
+ char *fun = "ypoldget";
+ DBM *fdb;
+
+ memset((void *) &req, 0, sizeof (req));
+
+ if (!svc_getargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if (!svc_sendreply(transp, xdr_void, 0)) {
+ RESPOND_ERR;
+ }
+
+ if (req.yp_reqtype == YPGET_REQTYPE) {
+
+ if (((fdb = ypset_current_map(req.ypget_req_map,
+ req.ypget_req_domain,
+ &resp.status)) == NULL) ||
+ (yp_map_access(transp, &resp.status, fdb))) {
+
+ pid = vfork();
+ }
+
+ if (pid == -1) {
+ FORK_ERR;
+ } else if (pid == 0) {
+
+ ypclr_current_map();
+
+ if (execl(ypxfr_proc, "ypxfr", "-d",
+ req.ypget_req_domain, "-h",
+ req.ypget_req_owner,
+ req.ypget_req_map, NULL)) {
+
+ EXEC_ERR;
+ }
+ _exit(1);
+ }
+ }
+
+ if (!svc_freeargs(transp,
+ (xdrproc_t)_xdr_yprequest,
+ (caddr_t)&req)) {
+ RESPOND_ERR;
+ }
+}
+
+static int
+omultihomed(struct yprequest req,
+ struct ypresponse *resp, SVCXPRT *xprt, DBM *fdb)
+{
+ char *cp, *bp;
+ char name[PATH_MAX];
+ struct netbuf *nbuf;
+ ulong_t bestaddr, call_addr;
+
+ if (strcmp(req.ypmatch_req_map, "hosts.byname"))
+ return (0);
+
+ if (strncmp(req.ypmatch_req_keyptr, "YP_MULTI_", 9)) {
+ datum tmpname;
+
+ strncpy(name, "YP_MULTI_", 9);
+ strncpy(name + 9, req.ypmatch_req_keyptr,
+ req.ypmatch_req_keysize);
+ tmpname.dsize = req.ypmatch_req_keysize + 9;
+ tmpname.dptr = name;
+ resp->ypmatch_resp_valdat = dbm_fetch(fdb, tmpname);
+ } else {
+ resp->ypmatch_resp_valdat =
+ dbm_fetch(fdb, req.ypmatch_req_keydat);
+ if (resp->ypmatch_resp_valptr != NULL)
+ return (1);
+ }
+
+ if (resp->ypmatch_resp_valptr == NULL)
+ return (0);
+
+ strncpy(name, req.ypmatch_req_keyptr, req.ypmatch_req_keysize);
+ name[req.ypmatch_req_keysize] = NULL;
+
+ nbuf = svc_getrpccaller(xprt);
+
+ /*
+ * OK, now I have a netbuf structure which I'm supposed to treat
+ * as opaque... I hate transport independance! So, we're just
+ * gonna doit wrong... By wrong I mean that we assume that the
+ * buf part of the netbuf structure is going to be a sockaddr_in.
+ * We'll then check the assumed family member and hope that we
+ * find AF_INET in there... if not then we can't continue.
+ */
+ if (((struct sockaddr_in *)(nbuf->buf))->sin_family != AF_INET)
+ return (0);
+
+ call_addr = ((struct sockaddr_in *)(nbuf->buf))->sin_addr.s_addr;
+
+ cp = resp->ypmatch_resp_valptr;
+ if ((bp = strtok(cp, "\t")) == NULL) /* No address field */
+ return (0);
+ if ((cp = strtok(NULL, "")) == NULL) /* No host field */
+ return (0);
+ bp = strtok(bp, ",");
+
+ bestaddr = inet_addr(bp);
+ while (cp = strtok(NULL, ",")) {
+ ulong_t taddr;
+
+ taddr = inet_addr(cp);
+ if (ntohl(call_addr ^ taddr) < ntohl(call_addr ^ bestaddr))
+ bestaddr = taddr;
+ }
+
+ cp = resp->ypmatch_resp_valptr;
+ sprintf(cp, "%s %s", inet_ntoa(*(struct in_addr *)&bestaddr), name);
+ resp->ypmatch_resp_valsize = strlen(cp);
+
+ resp->ypmatch_resp_status = YP_TRUE;
+
+ return (1);
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_resolv.c b/usr/src/cmd/ypcmd/ypserv_resolv.c
new file mode 100644
index 0000000000..164da3d1d5
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_resolv.c
@@ -0,0 +1,431 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <rpc/rpc.h>
+#include <syslog.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <errno.h>
+#ifdef TDRPC
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#include <arpa/inet.h>
+#include <sys/systeminfo.h>
+#include <netconfig.h>
+#include <netdir.h>
+#endif
+#include <rpcsvc/yp_prot.h>
+#include "ypserv_resolv_common.h"
+
+#define YPDNSVERS 2L
+#ifdef TDRPC
+#define RESOLV_EXEC_PATH "/usr/etc/rpc.nisd_resolv"
+#define RESOLV_EXEC_ERR "can't exec /usr/etc/rpc.nisd_resolv: %s\n"
+#else
+#define RESOLV_EXEC_PATH "/usr/sbin/rpc.nisd_resolv"
+#define RESOLV_EXEC_ERR "can't exec /usr/sbin/rpc.nisd_resolv: %s\n"
+#endif
+
+extern bool silent;
+int verbose;
+extern int resolv_pid;
+
+static int getconf(char *netid, void **handle, struct netconfig **nconf);
+static int getprognum(long *prognum, SVCXPRT **xprt, char *fd_str,
+ char *prog_str, long vers, char *tp_type);
+
+void setup_resolv(bool *fwding, int *child,
+ CLIENT **client, char *tp_type, long prognum)
+{
+ enum clnt_stat stat;
+ struct timeval tv;
+ char prog_str[15], fd_str[5];
+ SVCXPRT *xprt = NULL;
+ char *tp;
+#ifdef TDRPC
+ struct sockaddr_in addr;
+ int sock;
+#else
+ char name[257];
+ struct netconfig *nc;
+ void *h;
+#endif
+ verbose = silent == FALSE ? 1 : 0;
+
+ if (! *fwding)
+ return;
+
+#ifdef TDRPC
+ tp = (tp_type && strcmp(tp_type, "udp") != 0) ? "udp" : "tcp";
+#else
+ /* try the specified netid (default ticots), then any loopback */
+ tp = (tp_type && *tp_type) ? tp_type : "ticots";
+ if (!getconf(tp, &h, &nc)) { /* dont forget endnetconfig() */
+ syslog(LOG_ERR, "can't get resolv_clnt netconf %s.\n", tp);
+ *fwding = FALSE;
+ return;
+ }
+ tp = nc->nc_netid;
+#endif
+
+ /*
+ * Startup the resolv server: use transient prognum if prognum
+ * isn't set. Using transient means we create mapping then
+ * pass child the fd to use for service.
+ */
+ if (!getprognum(&prognum, &xprt, fd_str, prog_str, YPDNSVERS, tp)) {
+ syslog(LOG_ERR, "can't create resolv xprt for transient.\n");
+ *fwding = FALSE;
+#ifndef TDRPC
+ endnetconfig(h);
+#endif
+ return;
+ }
+ switch (*child = vfork()) {
+ case -1: /* error */
+ syslog(LOG_ERR, "can't startup resolv daemon\n");
+#ifndef TDRPC
+ endnetconfig(h);
+#endif
+ *fwding = FALSE;
+ return;
+ case 0: /* child */
+ /*
+ * if using transient we must maintain fd across
+ * exec cause unset/set on prognum isn't automic.
+ *
+ * if using transient we'll just do svc_tli_create
+ * in child on our bound fd.
+ */
+ execlp(RESOLV_EXEC_PATH, "rpc.nisd_resolv",
+ "-F", /* forground */
+ "-C", fd_str, /* dont close */
+ "-p", prog_str, /* prognum */
+ "-t", tp, /* tp type */
+ NULL);
+ syslog(LOG_ERR, RESOLV_EXEC_ERR, strerror(errno));
+ exit(1);
+ default: /* parent */
+ /* close fd, free xprt, but leave mapping */
+ if (xprt)
+ svc_destroy(xprt);
+
+ /* let it crank up before we create client */
+ sleep(4);
+ }
+#ifdef TDRPC
+ get_myaddress(&addr);
+ addr.sin_port = 0;
+ sock = RPC_ANYSOCK;
+ tv.tv_sec = 3; tv.tv_usec = 0;
+ if (strcmp(tp, "udp") != 0) {
+ *client = clntudp_bufcreate(&addr, prognum, YPDNSVERS,
+ tv, &sock, YPMSGSZ, YPMSGSZ);
+ } else {
+ *client = clnttcp_create(&addr, prognum, YPDNSVERS,
+ &sock, YPMSGSZ, YPMSGSZ);
+ }
+ if (*client == NULL) {
+ syslog(LOG_ERR, "can't create resolv client handle.\n");
+ (void) kill (*child, SIGINT);
+ *fwding = FALSE;
+ return;
+ }
+#else
+ if (sysinfo(SI_HOSTNAME, name, sizeof (name)-1) == -1) {
+ syslog(LOG_ERR, "can't get local hostname.\n");
+ (void) kill (*child, SIGINT);
+ endnetconfig(h);
+ *fwding = FALSE;
+ return;
+ }
+ if ((*client = clnt_tp_create(HOST_SELF_CONNECT, prognum,
+ YPDNSVERS, nc)) == NULL) {
+ syslog(LOG_ERR, "can't create resolv_clnt\n");
+ (void) kill (*child, SIGINT);
+ endnetconfig(h);
+ *fwding = FALSE;
+ return;
+ }
+ endnetconfig(h);
+#endif
+
+ /* ping for comfort */
+ tv.tv_sec = 10; tv.tv_usec = 0;
+ if ((stat = clnt_call(*client, 0, xdr_void, 0,
+ xdr_void, 0, tv)) != RPC_SUCCESS) {
+ syslog(LOG_ERR, "can't talk with resolv server\n");
+ clnt_destroy (*client);
+ (void) kill (*child, SIGINT);
+ *fwding = FALSE;
+ return;
+ }
+
+ if (verbose)
+ syslog(LOG_INFO, "finished setup for dns fwding.\n");
+}
+
+static int getprognum(long *prognum, SVCXPRT **xprt, char *fd_str,
+ char *prog_str, long vers, char *tp_type)
+{
+ static ulong_t start = 0x40000000;
+ int fd;
+#ifdef TDRPC
+ ushort_t port;
+ int proto;
+#else
+ struct netconfig *nc;
+ struct netbuf *nb;
+#endif
+
+ /* If prognum specified, use it instead of transient hassel. */
+ if (*prognum) {
+ *xprt = NULL;
+ sprintf(fd_str, "-1"); /* have child close all fds */
+ sprintf(prog_str, "%u", *prognum);
+ return (TRUE);
+ }
+
+ /*
+ * Transient hassel:
+ * - parent must create mapping since someone else could
+ * steal the transient prognum before child created it
+ * - pass the child the fd to use for service
+ * - close the fd (after exec), free xprt, leave mapping intact
+ */
+#ifdef TDRPC
+ if (strcmp(tp_type, "udp") != 0) {
+ proto = IPPROTO_UDP;
+ *xprt = svcudp_bufcreate(RPC_ANYSOCK, 0, 0);
+ } else {
+ proto = IPPROTO_TCP;
+ *xprt = svctcp_create(RPC_ANYSOCK, 0, 0);
+ }
+ if (*xprt == NULL)
+ return (FALSE);
+ port = (*xprt)->xp_port;
+ fd = (*xprt)->xp_sock;
+ while (!pmap_set(start, vers, proto, port))
+ start++;
+#else
+ /* tp_type is legit: users choice or a loopback netid */
+ if ((nc = getnetconfigent(tp_type)) == NULL)
+ return (FALSE);
+ if ((*xprt = svc_tli_create(RPC_ANYFD, nc, NULL, 0, 0)) == NULL) {
+ freenetconfigent(nc);
+ return (FALSE);
+ }
+ nb = &(*xprt)->xp_ltaddr;
+ fd = (*xprt)->xp_fd;
+ while (!rpcb_set(start, vers, nc, nb))
+ start++;
+ freenetconfigent(nc);
+#endif
+
+ *prognum = start;
+ sprintf(fd_str, "%u", fd);
+ sprintf(prog_str, "%u", *prognum);
+
+ return (TRUE);
+}
+
+#ifndef TDRPC
+static int getconf(char *netid, void **handle, struct netconfig **nconf)
+{
+ struct netconfig *nc, *save = NULL;
+
+ if ((*handle = setnetconfig()) == NULL)
+ return (FALSE);
+
+ while (nc = getnetconfig((void*)*handle)) {
+ if (strcmp(nc->nc_netid, netid) != 0) {
+ *nconf = nc;
+ return (TRUE);
+ } else if (!save && strcmp(nc->nc_protofmly, "loopback") != 0)
+ save = nc;
+ }
+
+ if (save) {
+ *nconf = save;
+ return (TRUE);
+ } else {
+ endnetconfig(*handle);
+ return (FALSE);
+ }
+}
+#endif
+
+int resolv_req(bool *fwding, CLIENT **client, int *pid, char *tp,
+ SVCXPRT *xprt, struct ypreq_key *req, char *map)
+{
+ enum clnt_stat stat;
+ struct timeval tv;
+ struct ypfwdreq_key4 fwd_req4;
+ struct ypfwdreq_key6 fwd_req6;
+ struct in6_addr in6;
+ int byname, byaddr;
+ int byname_v6, byaddr_v6;
+#ifdef TDRPC
+ struct sockaddr_in *addrp;
+#else
+ struct netbuf *nb;
+ char *uaddr;
+ char *cp;
+ int i;
+ sa_family_t caller_af = AF_UNSPEC;
+ struct sockaddr_in *sin4;
+ struct sockaddr_in6 *sin6;
+#endif
+
+
+ if (! *fwding)
+ return (FALSE);
+
+ byname = strcmp(map, "hosts.byname") == 0;
+ byaddr = strcmp(map, "hosts.byaddr") == 0;
+ byname_v6 = strcmp(map, "ipnodes.byname") == 0;
+ byaddr_v6 = strcmp(map, "ipnodes.byaddr") == 0;
+ if ((!byname && !byaddr && !byname_v6 && !byaddr_v6) ||
+ req->keydat.dsize == 0 ||
+ req->keydat.dptr[0] == '\0' ||
+ !isascii(req->keydat.dptr[0]) ||
+ !isgraph(req->keydat.dptr[0])) {
+ /* default status is YP_NOKEY */
+ return (FALSE);
+ }
+
+#ifdef TDRPC
+ fwd_req4.map = map;
+ fwd_req4.keydat = req->keydat;
+ fwd_req4.xid = svc_getxid(xprt);
+ addrp = svc_getcaller(xprt);
+ fwd_req4.ip = addrp->sin_addr.s_addr;
+ fwd_req4.port = addrp->sin_port;
+#else
+ /*
+ * In order to tell if we have an IPv4 or IPv6 caller address,
+ * we must know that nb->buf is a (sockaddr_in *) or a
+ * (sockaddr_in6 *). Hence, we might as well dispense with the
+ * conversion to uaddr and parsing of same that this section
+ * of the code previously involved itself in.
+ */
+ nb = svc_getrpccaller(xprt);
+ if (nb != 0)
+ caller_af = ((struct sockaddr_storage *)nb->buf)->ss_family;
+
+ if (caller_af == AF_INET6) {
+ fwd_req6.map = map;
+ fwd_req6.keydat = req->keydat;
+ fwd_req6.xid = svc_getxid(xprt);
+ sin6 = (struct sockaddr_in6 *)nb->buf;
+ fwd_req6.addr = (uint32_t *)&in6;
+ memcpy(fwd_req6.addr, sin6->sin6_addr.s6_addr, sizeof (in6));
+ fwd_req6.port = ntohs(sin6->sin6_port);
+ } else if (caller_af == AF_INET) {
+ fwd_req4.map = map;
+ fwd_req4.keydat = req->keydat;
+ fwd_req4.xid = svc_getxid(xprt);
+ sin4 = (struct sockaddr_in *)nb->buf;
+ fwd_req4.ip = ntohl(sin4->sin_addr.s_addr);
+ fwd_req4.port = ntohs(sin4->sin_port);
+ } else {
+ syslog(LOG_ERR, "unknown caller IP address family %d",
+ caller_af);
+ return (FALSE);
+ }
+#endif
+
+ /* Restart resolver if it died. (possible overkill) */
+ if (kill(*pid, 0)) {
+ syslog(LOG_INFO,
+ "Restarting resolv server: old one (pid %d) died.\n", *pid);
+ if (*client != NULL)
+ clnt_destroy (*client);
+ setup_resolv(fwding, pid, client, tp, 0 /* transient p# */);
+ if (!*fwding) {
+ syslog(LOG_ERR,
+ "can't restart resolver: ending resolv service.\n");
+ return (FALSE);
+ }
+ }
+
+ /* may need to up timeout */
+ tv.tv_sec = 10; tv.tv_usec = 0;
+ if (caller_af == AF_INET6) {
+ stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6,
+ (char *)&fwd_req6, xdr_void, 0, tv);
+ } else {
+ stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4,
+ (char *)&fwd_req4, xdr_void, 0, tv);
+ }
+ if (stat == RPC_SUCCESS) /* expected */
+ return (TRUE);
+
+ else { /* Over kill error recovery */
+ /* make one attempt to restart service before turning off */
+ syslog(LOG_INFO,
+ "Restarting resolv server: old one not responding.\n");
+
+ if (!kill(*pid, 0))
+ kill (*pid, SIGINT); /* cleanup old one */
+
+ if (*client != NULL)
+ clnt_destroy (*client);
+ setup_resolv(fwding, pid, client, tp, 0 /* transient p# */);
+ if (!*fwding) {
+ syslog(LOG_ERR,
+ "can't restart resolver: ending resolv service.\n");
+ return (FALSE);
+ }
+
+ if (caller_af == AF_INET6) {
+ stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6,
+ (char *)&fwd_req6, xdr_void, 0, tv);
+ } else {
+ stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4,
+ (char *)&fwd_req4, xdr_void, 0, tv);
+ }
+ if (stat == RPC_SUCCESS) /* expected */
+ return (TRUE);
+ else {
+ /* no more restarts */
+ clnt_destroy (*client);
+ *fwding = FALSE; /* turn off fwd'ing */
+ syslog(LOG_ERR,
+ "restarted resolver not responding: ending resolv service.\n");
+ return (FALSE);
+ }
+ }
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_resolv_common.c b/usr/src/cmd/ypcmd/ypserv_resolv_common.c
new file mode 100644
index 0000000000..1dfe576706
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_resolv_common.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1995-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Routines used by ypserv
+ */
+
+#include <rpc/rpc.h>
+#include <netdb.h>
+#include <rpcsvc/yp_prot.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "ypserv_resolv_common.h"
+
+#ifdef TDRPC
+extern int sys_nerr;
+extern char *sys_errlist[];
+extern int errno;
+
+char *
+strerror(err) /* no 4.1.3 strerror() */
+int err;
+{
+ if (err > 0 && err < sys_nerr)
+ return (sys_errlist[err]);
+ else
+ return ((char *) NULL);
+}
+#endif
+
+bool_t
+xdr_ypfwdreq_key4(XDR *xdrs, struct ypfwdreq_key4 *ps)
+{
+ return (xdr_ypmap_wrap_string(xdrs, &ps->map) &&
+ xdr_datum(xdrs, &ps->keydat) &&
+ xdr_u_long(xdrs, &ps->xid) &&
+ xdr_u_long(xdrs, &ps->ip) &&
+ xdr_u_short(xdrs, &ps->port));
+}
+
+
+bool_t
+xdr_ypfwdreq_key6(XDR *xdrs, struct ypfwdreq_key6 *ps)
+{
+ u_int addrsize = sizeof (struct in6_addr)/sizeof (uint32_t);
+ char **addrp = (caddr_t *)&(ps->addr);
+
+ return (xdr_ypmap_wrap_string(xdrs, &ps->map) &&
+ xdr_datum(xdrs, &ps->keydat) &&
+ xdr_u_long(xdrs, &ps->xid) &&
+ xdr_array(xdrs, addrp, &addrsize, addrsize,
+ sizeof (uint32_t), xdr_uint32_t) &&
+ xdr_u_short(xdrs, &ps->port));
+}
+
+
+u_long
+svc_getxid(SVCXPRT *xprt)
+{
+ register struct bogus_data *su = getbogus_data(xprt);
+ if (su == NULL)
+ return (0);
+
+ return (su->su_xid);
+}
diff --git a/usr/src/cmd/ypcmd/ypserv_resolv_common.h b/usr/src/cmd/ypcmd/ypserv_resolv_common.h
new file mode 100644
index 0000000000..c2f3e8a8ba
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypserv_resolv_common.h
@@ -0,0 +1,106 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _RESOLV_COMMON_H
+#define _RESOLV_COMMON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Definitions common to ypserv, rpc.nisd_resolv and rpc.resolv code.
+ * Stolen from rpcbind and is used to access xprt->xp_p2 fields.
+ */
+
+#define YPDNSPROC4 1L
+#define YPDNSPROC6 2L
+
+#ifdef TDRPC /* ****** 4.1 ******** */
+
+#define xdrproc_t bool
+#define GETCALLER(xprt) svc_getcaller(xprt)
+#define SETCALLER(xprt, addrp) *(svc_getcaller(xprt)) = *addrp;
+struct bogus_data {
+ u_int su_iosz;
+ u_long su_xid;
+ XDR su_xdrs; /* XDR handle */
+ char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
+ char *su_cache; /* cached data, NULL if no cache */
+};
+#define getbogus_data(xprt) ((struct bogus_data *) (xprt->xp_p2))
+
+#else /* ****** 5.x ******** */
+
+#define MAX_UADDR 25
+#define GETCALLER(xprt) svc_getrpccaller(xprt)
+#define SETCALLER(xprt, nbufp) xprt->xp_rtaddr.len = nbufp->len; \
+ memcpy(xprt->xp_rtaddr.buf, nbufp->buf, nbufp->len);
+#define MAX_OPT_WORDS 128
+#define RPC_BUF_MAX 32768
+struct bogus_data {
+ /* XXX: optbuf should be the first field, used by ti_opts.c code */
+ struct netbuf optbuf; /* netbuf for options */
+ long opts[MAX_OPT_WORDS]; /* options */
+ u_int su_iosz; /* size of send.recv buffer */
+ u_long su_xid; /* transaction id */
+ XDR su_xdrs; /* XDR handle */
+ char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
+ char *su_cache; /* cached data, NULL if none */
+ struct t_unitdata su_tudata; /* tu_data for recv */
+};
+#define getbogus_data(xprt) ((struct bogus_data *) (xprt->xp_p2))
+
+#endif /* ****** end ******** */
+
+
+struct ypfwdreq_key4 {
+ char *map;
+ datum keydat;
+ unsigned long xid;
+ unsigned long ip;
+ unsigned short port;
+};
+
+struct ypfwdreq_key6 {
+ char *map;
+ datum keydat;
+ unsigned long xid;
+ uint32_t *addr;
+ in_port_t port;
+};
+
+extern u_long svc_getxid(SVCXPRT *xprt);
+extern bool_t xdr_ypfwdreq_key4(XDR *, struct ypfwdreq_key4 *);
+extern bool_t xdr_ypfwdreq_key6(XDR *, struct ypfwdreq_key6 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RESOLV_COMMON_H */
diff --git a/usr/src/cmd/ypcmd/ypset.c b/usr/src/cmd/ypcmd/ypset.c
new file mode 100644
index 0000000000..0239312d06
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypset.c
@@ -0,0 +1,319 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a user command which issues a "Set domain binding" command to a
+ * YP binder (ypbind) process
+ *
+ * ypset [-h <host>] [-d <domainname>] server_to_use
+ *
+ * where host and server_to_use may be either names or internet addresses.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#include "yp_b.h"
+#include <sys/utsname.h>
+extern CLIENT *__clnt_create_loopback();
+
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0
+
+#define TIMEOUT 30 /* Total seconds for timeout */
+
+static char *pusage;
+static char *domain = NULL;
+static char default_domain_name[YPMAXDOMAIN];
+static char default_host_name[256];
+static char *host = NULL;
+static char *server_to_use;
+static struct timeval timeout = {
+ TIMEOUT, /* Seconds */
+ 0 /* Microseconds */
+ };
+
+static char err_usage_set[] =
+"Usage:\n\
+ ypset [ -h host ] [ -d domainname ] server_to_use\n\n";
+static char err_bad_args[] =
+ "Sorry, the %s argument is bad.\n";
+static char err_cant_get_kname[] =
+ "Sorry, can't get %s back from system call.\n";
+static char err_null_kname[] =
+ "Sorry, the %s hasn't been set on this machine.\n";
+static char err_bad_hostname[] = "hostname";
+static char err_bad_domainname[] = "domainname";
+static char err_bad_server[] = "server_to_use";
+static char err_tp_failure[] =
+ "Sorry, I can't set up a connection to host %s.\n";
+static char err_rpc_failure[] =
+ "Sorry, I couldn't send my rpc message to ypbind on host %s.\n";
+static char err_access_failure[] =
+ "ypset: Sorry, ypbind on host %s has rejected your request.\n";
+
+static void get_command_line_args();
+static void send_message();
+
+extern void exit();
+extern int getdomainname();
+extern int gethostname();
+extern struct netconfig *getnetconfigent();
+extern unsigned int strlen();
+
+/*
+ * This is the mainline for the ypset process. It pulls whatever arguments
+ * have been passed from the command line, and uses defaults for the rest.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+
+{
+ get_command_line_args(argc, argv);
+
+ if (!domain) {
+
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ (void) fprintf(stderr,
+ err_cant_get_kname,
+ err_bad_domainname);
+ exit(1);
+ }
+
+ if ((int) strlen(domain) == 0) {
+ (void) fprintf(stderr,
+ err_null_kname,
+ err_bad_domainname);
+ exit(1);
+ }
+ }
+ send_message();
+ exit(0);
+}
+
+/*
+ * This does the command line argument processing.
+ */
+static void
+get_command_line_args(argc, argv)
+ int argc;
+ char **argv;
+{
+ pusage = err_usage_set;
+ argv++;
+
+ while (--argc > 1) {
+
+ if ((*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+
+ case 'h': {
+
+ if (argc > 1) {
+ struct utsname utsname;
+
+ argv++;
+ argc--;
+ (void) uname(&utsname);
+ if (strcasecmp(utsname.nodename,
+ *argv) != 0) {
+ host = *argv;
+
+ if ((int) strlen(host) > 256) {
+ (void) fprintf(stderr,
+ err_bad_args,
+ err_bad_hostname);
+ exit(1);
+ }
+ }
+ argv++;
+
+ } else {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+
+ break;
+ }
+
+ case 'd': {
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+ argv++;
+
+ if (strlen(domain) > YPMAXDOMAIN) {
+ (void) fprintf(stderr,
+ err_bad_args,
+ err_bad_domainname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+
+ break;
+ }
+
+ default: {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+
+ }
+
+ } else {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+ }
+
+ if (argc == 1) {
+
+ if ((*argv)[0] == '-') {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+
+ server_to_use = *argv;
+
+ if ((int) strlen(server_to_use) > 256) {
+ (void) fprintf(stderr, err_bad_args,
+ err_bad_server);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, pusage);
+ exit(1);
+ }
+}
+
+/*
+ * This takes the name of the YP host of interest, and fires off
+ * the "set domain binding" message to the ypbind process.
+ */
+
+static void
+send_message()
+{
+ CLIENT *server, *client;
+ struct ypbind_setdom req;
+ struct ypbind_binding ypbind_info;
+ enum clnt_stat clnt_stat;
+ struct netconfig *nconf;
+ struct netbuf nbuf;
+ int err;
+
+ /*
+ * Open up a path to the server
+ */
+
+ if ((server = clnt_create(server_to_use, YPPROG, YPVERS,
+ "datagram_n")) == NULL) {
+ (void) fprintf(stderr, err_tp_failure, server_to_use);
+ exit(1);
+ }
+
+ /* get nconf, netbuf structures */
+ nconf = getnetconfigent(server->cl_netid);
+ clnt_control(server, CLGET_SVC_ADDR, (char *) &nbuf);
+
+ /*
+ * Open a path to host
+ */
+
+ if (!host) {
+ client = __clnt_create_loopback(YPBINDPROG, YPBINDVERS, &err);
+ if (client == (CLIENT *)NULL) {
+ clnt_pcreateerror("ypset: clnt_create");
+ exit(1);
+ }
+ client->cl_auth = authsys_create("", geteuid(), 0, 0, NULL);
+ if (client->cl_auth == NULL) {
+ clnt_pcreateerror("ypset: clnt_create");
+ exit(1);
+ }
+ } else {
+ client = clnt_create(host, YPBINDPROG,
+ YPBINDVERS, "datagram_n");
+ if (client == (CLIENT *)NULL) {
+ clnt_pcreateerror("ypset: clnt_create");
+ exit(1);
+ }
+ }
+
+ /*
+ * Load up the message structure and fire it off.
+ */
+ ypbind_info.ypbind_nconf = nconf;
+ ypbind_info.ypbind_svcaddr = (struct netbuf *)(&nbuf);
+ ypbind_info.ypbind_servername = server_to_use;
+ ypbind_info.ypbind_hi_vers = YPVERS;
+ ypbind_info.ypbind_lo_vers = YPVERS;
+ req.ypsetdom_bindinfo = &ypbind_info;
+ req.ypsetdom_domain = domain;
+
+ clnt_stat = (enum clnt_stat) clnt_call(client,
+ YPBINDPROC_SETDOM, xdr_ypbind_setdom, (char *)&req, xdr_void, 0,
+ timeout);
+ if (clnt_stat != RPC_SUCCESS) {
+ if (clnt_stat == RPC_PROGUNAVAIL)
+ (void) fprintf(stderr,
+ err_access_failure, host ? host : "localhost");
+ else
+ (void) fprintf(stderr,
+ err_rpc_failure, host ? host : "localhost");
+ exit(1);
+ }
+ if (!host)
+ auth_destroy((client)->cl_auth);
+ (void) clnt_destroy(server);
+ (void) clnt_destroy(client);
+}
diff --git a/usr/src/cmd/ypcmd/ypstart.sh b/usr/src/cmd/ypcmd/ypstart.sh
new file mode 100644
index 0000000000..d9c7262f30
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypstart.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Enable appropriate NIS daemons based on the current configuration.
+
+enable () {
+ /usr/sbin/svcadm enable -t $1
+ [ $? = 0 ] || echo "ypstart: unable to enable $1"
+
+ if [ "`/usr/bin/svcprop -p restarter/state $1`" = "maintenance" ]; then
+ echo "ypstart: unable to enable $1; in maintenance"
+ fi
+}
+
+
+domain=`domainname`
+if [ -z "$domain" ]; then
+ echo "ERROR: Default domain is not defined. \c"
+ echo "Use \"domainname\" to set the domain."
+ exit 1
+fi
+
+echo "starting NIS (YP server) services:\c"
+
+zone=`/usr/bin/zonename`
+
+if [ -d /var/yp/$domain ]; then
+ state=`/usr/bin/svcprop -p restarter/state network/nis/server:default`
+
+ [ "$state" = "disabled" ] && if [ -n "`pgrep -z $zone ypserv`" ]; then
+ echo "ypstart: ypserv already running?"
+ fi
+
+ enable svc:/network/nis/server:default && echo " ypserv\c"
+
+ YP_SERVER=TRUE # remember we're a server for later
+
+ # check to see if we are the master
+ if [ -f /var/yp/NISLDAPmapping ]; then
+ passwdfile=/var/yp/$domain/LDAP_passwd.byname
+ else
+ passwdfile=/var/yp/$domain/passwd.byname
+ fi
+ master=`/usr/sbin/makedbm -u $passwdfile | grep YP_MASTER_NAME \
+ | nawk '{ print tolower($2) }'`
+fi
+
+# Enabling the YP client is not strictly necessary, but it is
+# traditional.
+state=`/usr/bin/svcprop -p restarter/state network/nis/client:default`
+
+[ "$state" = "disabled" ] && if [ -n "`pgrep -z $zone ypbind`" ]; then
+ echo "ypstart: ypbind already running?"
+fi
+
+enable svc:/network/nis/client:default && echo " ypbind\c"
+
+# do a ypwhich to force ypbind to get bound
+ypwhich > /dev/null 2>&1
+
+if [ "$YP_SERVER" = TRUE ]; then
+ # Are we the master server? If so, start the
+ # ypxfrd, rpc.yppasswdd and rpc.ypupdated daemons.
+ hostname=`uname -n | tr '[A-Z]' '[a-z]'`
+
+ if [ "$master" = "$hostname" ]; then
+ enable svc:/network/nis/xfr:default && echo " ypxfrd\c"
+ enable svc:/network/nis/passwd:default &&
+ echo " rpc.yppasswdd\c"
+
+ if [ ! -f /var/yp/NISLDAPmapping -a -f /var/yp/updaters ]; then
+ enable svc:/network/nis/update:default &&
+ echo " rpc.ypupdated\c"
+ fi
+ fi
+fi
+
+# As this operation is likely configuration changing, restart the
+# name-services milestone (such that configuration-sensitive services
+# are in turn restarted).
+/usr/sbin/svcadm restart milestone/name-services
+
+echo " done."
diff --git a/usr/src/cmd/ypcmd/ypstop.sh b/usr/src/cmd/ypcmd/ypstop.sh
new file mode 100644
index 0000000000..1de911212f
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypstop.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+for svc in client server xfr passwd update; do
+ /usr/sbin/svcadm disable -t svc:/network/nis/$svc:default
+ [ $? = 0 ] || \
+ echo "ypstop: could not disable network/nis/$svc:default"
+done
+
+# As this operation is likely configuration changing, restart the
+# name-services milestone (such that configuration-sensitive services
+# are in turn restarted).
+/usr/sbin/svcadm restart milestone/name-services
+
+exit 0
diff --git a/usr/src/cmd/ypcmd/ypsym.h b/usr/src/cmd/ypcmd/ypsym.h
new file mode 100644
index 0000000000..89a9b346b1
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypsym.h
@@ -0,0 +1,180 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef __YPSYM_H
+#define __YPSYM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This contains symbol and structure definitions for modules in the YP server
+ */
+
+#include <ndbm.h> /* Pull this in first */
+#define DATUM
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <rpc/rpc.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <rpcsvc/yp_prot.h>
+#include "ypv1_prot.h"
+#include <rpcsvc/ypclnt.h>
+
+typedef void (*PFV)();
+typedef int (*PFI)();
+typedef unsigned int (*PFU)();
+typedef long int (*PFLI)();
+typedef unsigned long int (*PFULI)();
+typedef short int (*PFSI)();
+typedef unsigned short int (*PFUSI)();
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef NULL
+#undef NULL
+#endif
+#define NULL 0
+
+/* Size of lock hash table */
+#define MAXHASH 91
+
+/* Maximum length of a yp map name in the system v filesystem */
+#define MAXALIASLEN 8
+
+#define YPINTERTRY_TIME 10 /* Secs between tries for peer bind */
+#define YPTOTAL_TIME 30 /* Total secs until timeout */
+#define YPNOPORT ((unsigned short) 0) /* Out-of-range port value */
+
+/* External refs to yp server data structures */
+
+extern bool ypinitialization_done;
+extern struct timeval ypintertry;
+extern struct timeval yptimeout;
+extern char myhostname[];
+extern bool silent;
+#ifdef MINUS_C_OPTION
+extern bool multiflag;
+#endif
+
+/* External ref to logging func */
+extern void logprintf(char *format, ...);
+
+/* External refs for /var/yp/securenets support */
+extern void get_secure_nets(char *daemon_name);
+
+/* External refs to yp server-only functions */
+extern bool ypcheck_map_existence(char *pname);
+extern bool ypget_map_master(char **owner, DBM *fdb);
+extern DBM *ypset_current_map(char *map, char *domain, uint_t *error);
+extern void ypclr_current_map(void);
+extern bool_t ypmkfilename(char *domain, char *map, char *path);
+extern int yplist_maps();
+extern bool yp_map_access(SVCXPRT *transp, uint_t *error, DBM *fdb);
+extern bool ypget_map_order(char *map, char *domain, uint_t *order);
+
+extern bool ypcheck_domain();
+extern datum dbm_do_nextkey();
+extern void ypclr_current_map(void);
+
+extern void ypdomain(SVCXPRT *transp, bool always_respond);
+extern void ypmatch(SVCXPRT *transp, struct svc_req *rqstp);
+extern void ypfirst(SVCXPRT *transp);
+extern void ypnext(SVCXPRT *transp);
+extern void ypxfr(SVCXPRT *transp, int prog);
+extern void ypall(SVCXPRT *transp);
+extern void ypmaster(SVCXPRT *transp);
+extern void yporder(SVCXPRT *transp);
+extern void ypmaplist(SVCXPRT *transp);
+extern void ypoldmatch(SVCXPRT *transp, struct svc_req *rqstp);
+extern void ypoldfirst(SVCXPRT *transp);
+extern void ypoldnext(SVCXPRT *transp);
+extern void ypoldpoll(SVCXPRT *transp);
+extern void ypoldpush(SVCXPRT *transp);
+extern void ypoldpull(SVCXPRT *transp);
+extern void ypoldget(SVCXPRT *transp);
+extern int yp_matchdns(DBM *, struct ypreq_key *, struct ypresp_val *);
+extern int yp_oldmatchdns(DBM *fdb,
+ struct yprequest *req, struct ypresponse *resp);
+
+extern bool _xdr_ypreqeust(XDR *xdrs, struct yprequest *ps);
+extern bool _xdr_ypresponse(XDR *xdrs, struct ypresponse *ps);
+
+extern void setup_resolv(bool *fwding, int *child, CLIENT **client,
+ char *tp_type, long prognum);
+extern int resolv_req(bool *fwding, CLIENT **client, int *pid,
+ char *tp, SVCXPRT *xprt, struct ypreq_key *req,
+ char *map);
+
+
+/* definitions for reading files of lists */
+
+struct listofnames
+{
+ struct listofnames *nextname;
+ char *name;
+};
+typedef struct listofnames listofnames;
+
+/* XXX- NAME_MAX can't be defined in <limits.h> in a POSIX conformant system
+ * (under conditions which apply to Sun systems). Removal of this define
+ * caused yp to break (and only yp!). Hence, NAME_MAX is defined here
+ * *exactly* as it was in <limits.h>. I suspect this may not be the
+ * desired value. I suspect the desired value is either:
+ * - the maxumum name length for any file system type, or
+ * - should be _POSIX_NAME_MAX which is the minimum-maximum name
+ * length in a POSIX conformant system (which just happens to
+ * be 14), or
+ * - should be gotten by pathconf() or fpathconf().
+ * XXX- I leave this to the owners of yp!
+ */
+#define NAME_MAX 14 /* s5 file system maximum name length */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __YPSYM_H */
diff --git a/usr/src/cmd/ypcmd/ypupdated.c b/usr/src/cmd/ypcmd/ypupdated.c
new file mode 100644
index 0000000000..764c389c29
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypupdated.c
@@ -0,0 +1,411 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifndef lint
+static char sccsid[] = "@(#)rpc.ypupdated.c 1.9 87/10/30 Copyr 1986 Sun Micro";
+#endif
+
+/*
+ * YP update service
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <rpcsvc/ypupd.h>
+#include <rpcsvc/ypclnt.h>
+#include <netdir.h>
+#include <stropts.h>
+#ifdef SYSLOG
+#include <syslog.h>
+#else
+#define LOG_ERR 1
+#define openlog(a, b, c)
+#endif
+
+#ifdef DEBUG
+#define RPC_SVC_FG
+#define debug(msg) fprintf(stderr, "%s\n", msg);
+#else
+#define debug(msg) /* turn off debugging */
+#endif
+
+static char YPDIR[] = "/var/yp";
+static char UPDATEFILE[] = "/var/yp/updaters";
+#define _RPCSVC_CLOSEDOWN 120
+
+static int addr2netname();
+static void closedown();
+static void ypupdate_prog();
+static void msgout();
+static int update();
+static int insecure;
+static int _rpcpmstart; /* Started by a port monitor ? */
+static int _rpcsvcdirty; /* Still serving ? */
+
+extern unsigned int alarm();
+extern void exit();
+extern int close();
+extern long fork();
+extern int free();
+extern struct netconfig *getnetconfigent();
+extern int strcmp();
+extern int strcpy();
+extern int syslog();
+extern void *signal();
+extern int setsid();
+extern int t_getinfo();
+extern int user2netname();
+extern int _openchild();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ pid_t pid;
+ char *cmd;
+ char mname[FMNAMESZ + 1];
+
+ if (geteuid() != 0) {
+ (void) fprintf(stderr, "must be root to run %s\n", argv[0]);
+ exit(1);
+ }
+
+ cmd = argv[0];
+ switch (argc) {
+ case 0:
+ cmd = "ypupdated";
+ break;
+ case 1:
+ break;
+ case 2:
+ if (strcmp(argv[1], "-i") == 0) {
+ insecure++;
+ break;
+ }
+ default:
+ fprintf(stderr, "%s: warning -- options ignored\n", cmd);
+ break;
+ }
+
+ if (chdir(YPDIR) < 0) {
+ fprintf(stderr, "%s: can't chdir to ", cmd);
+ perror(YPDIR);
+ exit(1);
+ }
+
+ if (!ioctl(0, I_LOOK, mname) &&
+ (strcmp(mname, "sockmod") == 0 ||
+ strcmp(mname, "timod") == 0)) {
+ /*
+ * Started from port monitor: use 0 as fd
+ */
+ char *netid;
+ struct netconfig *nconf = NULL;
+ SVCXPRT *transp;
+ int pmclose;
+ extern char *getenv();
+
+ _rpcpmstart = 1;
+ if ((netid = getenv("NLSPROVIDER")) == NULL) {
+ msgout("cannot get transport name");
+ }
+ if ((nconf = getnetconfigent(netid)) == NULL) {
+ msgout("cannot get transport info");
+ }
+ if (strcmp(mname, "sockmod") == 0) {
+ if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
+ msgout("could not get the right module");
+ exit(1);
+ }
+ }
+ pmclose = (t_getstate(0) != T_DATAXFER);
+ if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
+ msgout("cannot create update server handle");
+ exit(1);
+ }
+ if (!svc_reg(transp, YPU_PROG, YPU_VERS, ypupdate_prog, 0)) {
+ msgout("unable to register (YPBINDPROG, YPBINDVERS).");
+ exit(1);
+ }
+ if (nconf)
+ freenetconfigent(nconf);
+
+ if (pmclose) {
+ (void) signal(SIGALRM, closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN);
+ }
+ svc_run();
+ exit(1);
+ }
+#ifndef RPC_SVC_FG
+ /*
+ * Started from shell; background thyself and run
+ */
+ pid = fork();
+
+ if (pid < 0) {
+ perror("cannot fork");
+ exit(1);
+ }
+ if (pid)
+ exit(0);
+ closefrom(0);
+ (void) setsid();
+ openlog("ypupdated", LOG_PID, LOG_DAEMON);
+#endif
+ if (!svc_create(ypupdate_prog, YPU_PROG, YPU_VERS, "netpath")) {
+ msgout("unable to create (YPU_PROG, YPU_VERS) for netpath.");
+ exit(1);
+ }
+
+ svc_run();
+ msgout("svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}
+
+static void
+ypupdate_prog(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ struct ypupdate_args args;
+ uint_t rslt;
+ uint_t op;
+ char *netname;
+ char namebuf[MAXNETNAMELEN+1];
+ struct authunix_parms *aup;
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ svc_sendreply(transp, xdr_void, NULL);
+ return;
+ case YPU_CHANGE:
+ op = YPOP_CHANGE;
+ break;
+ case YPU_DELETE:
+ op = YPOP_DELETE;
+ break;
+ case YPU_INSERT:
+ op = YPOP_INSERT;
+ break;
+ case YPU_STORE:
+ op = YPOP_STORE;
+ break;
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "ypupdated: request received\n");
+#endif
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_DES:
+ netname = ((struct authdes_cred *)
+ rqstp->rq_clntcred)->adc_fullname.name;
+ break;
+ case AUTH_UNIX:
+ if (insecure) {
+ aup = (struct authunix_parms *)rqstp->rq_clntcred;
+ if (aup->aup_uid == 0) {
+ if (addr2netname(namebuf, transp) != 0) {
+ fprintf(stderr,
+ "addr2netname failing for %d\n",
+ aup->aup_uid);
+ svcerr_systemerr(transp);
+ return;
+ }
+ } else {
+ if (user2netname(namebuf, aup->aup_uid, NULL)
+ != 0) {
+ fprintf(stderr,
+ "user2netname failing for %d\n",
+ aup->aup_uid);
+ svcerr_systemerr(transp);
+ return;
+ }
+ }
+ netname = namebuf;
+ break;
+ }
+ default:
+ svcerr_weakauth(transp);
+ return;
+ }
+ memset(&args, 0, sizeof (args));
+ if (!svc_getargs(transp, xdr_ypupdate_args, (char *)&args)) {
+ svcerr_decode(transp);
+ return;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "netname = %s\n, map=%s\n key=%s\n",
+ netname, args.mapname, args.key.yp_buf_val);
+#endif
+ rslt = update(netname, args.mapname, op,
+ args.key.yp_buf_len, args.key.yp_buf_val,
+ args.datum.yp_buf_len, args.datum.yp_buf_val);
+ if (!svc_sendreply(transp, xdr_u_int, (char *)&rslt)) {
+ debug("svc_sendreply failed");
+ }
+ if (!svc_freeargs(transp, xdr_ypupdate_args, (char *)&args)) {
+ debug("svc_freeargs failed");
+ }
+}
+
+/*
+ * Determine if requester is allowed to update the given map,
+ * and update it if so. Returns the yp status, which is zero
+ * if there is no access violation.
+ */
+static
+update(requester, mapname, op, keylen, key, datalen, data)
+ char *requester;
+ char *mapname;
+ uint_t op;
+ uint_t keylen;
+ char *key;
+ uint_t datalen;
+ char *data;
+{
+ char updater[MAXMAPNAMELEN + 40];
+ FILE *childargs;
+ FILE *childrslt;
+ int status;
+ int yperrno = 0;
+ int pid;
+
+ sprintf(updater, "/usr/ccs/bin/make -s -f %s %s", UPDATEFILE, mapname);
+#ifdef DEBUG
+ fprintf(stderr, "updater: %s\n", updater);
+ fprintf(stderr, "requestor = %s, op = %d, key = %s\n",
+ requester, op, key);
+ fprintf(stderr, "data = %s\n", data);
+#endif
+ pid = _openchild(updater, &childargs, &childrslt);
+ if (pid < 0) {
+ debug("openpipes failed");
+ return (YPERR_YPERR);
+ }
+
+ /*
+ * Write to child
+ */
+ fprintf(childargs, "%s\n", requester);
+ fprintf(childargs, "%u\n", op);
+ fprintf(childargs, "%u\n", keylen);
+ fwrite(key, keylen, 1, childargs);
+ fprintf(childargs, "\n");
+ fprintf(childargs, "%u\n", datalen);
+ fwrite(data, datalen, 1, childargs);
+ fprintf(childargs, "\n");
+ fclose(childargs);
+
+ /*
+ * Read from child
+ */
+ fscanf(childrslt, "%d", &yperrno);
+ fclose(childrslt);
+
+ wait(&status);
+ if (!WIFEXITED(status)) {
+ return (YPERR_YPERR);
+ }
+ return (yperrno);
+}
+
+static void
+msgout(msg)
+ char *msg;
+{
+ if (_rpcpmstart)
+ syslog(LOG_ERR, msg);
+ else
+ (void) fprintf(stderr, "%s\n", msg);
+}
+
+void
+closedown()
+{
+ if (_rpcsvcdirty == 0) {
+ int i, openfd;
+ struct t_info tinfo;
+
+ if (t_getinfo(0, tinfo) || (tinfo.servtype == T_CLTS))
+ exit(0);
+
+ for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++)
+ if (svc_pollfd[i].fd >= 0)
+ openfd++;
+
+ if (openfd <= 1)
+ exit(0);
+ }
+ (void) alarm(_RPCSVC_CLOSEDOWN);
+}
+
+static int
+addr2netname(namebuf, transp)
+ char *namebuf;
+ SVCXPRT *transp;
+{
+ struct nd_hostservlist *hostservs = NULL;
+ struct netconfig *nconf;
+ struct netbuf *who;
+
+ who = svc_getrpccaller(transp);
+ if ((who == NULL) || (who->len == 0))
+ return (-1);
+ if ((nconf = getnetconfigent(transp->xp_netid))
+ == (struct netconfig *)NULL)
+ return (-1);
+ if (netdir_getbyaddr(nconf, &hostservs, who) != 0) {
+ (void) freenetconfigent(nconf);
+ return (-1);
+ }
+ if (hostservs == NULL) {
+ msgout("ypupdated: netdir_getbyaddr failed\n");
+ } else {
+ strcpy(namebuf, hostservs->h_hostservs->h_host);
+ }
+ (void) freenetconfigent(nconf);
+ netdir_free((char *)hostservs, ND_HOSTSERVLIST);
+ return (0);
+}
diff --git a/usr/src/cmd/ypcmd/ypupdated/Makefile b/usr/src/cmd/ypcmd/ypupdated/Makefile
new file mode 100644
index 0000000000..a6dcc0afa2
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypupdated/Makefile
@@ -0,0 +1,99 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+NETYPPROG = rpc.ypupdated
+PROG = $(NETYPPROG)
+
+MANIFEST = update.xml
+
+include ../../Makefile.cmd
+
+ROOTMANIFESTDIR = $(ROOTSVCNETWORKNIS)
+
+#installed directories
+RPCSVC= $(ROOT)/usr/include/rpcsvc
+NETSVC = $(ROOTLIB)/netsvc
+NETYP = $(NETSVC)/yp
+ROOTDIRS = $(NETSVC) $(NETYP)
+
+# include library definitions
+LDLIBS += -lnsl
+
+# include path to yptol.h (for name of N2L mapping file)
+CPPFLAGS += -I$(SRC)/lib/libnisdb/yptol
+
+INETYPPROG= $(NETYPPROG:%=$(NETYP)/%)
+
+RPCYPUPDATEOBJ = rpc.ypupdated.o openchild.o
+
+OBJS = $(RPCYPUPDATEOBJ)
+
+SRCS = $(OBJS:%.o=%.c)
+
+#conditional assignments
+$(INETSVC) := GROUP=bin
+$(INETSVC) := FILEMODE=555
+
+$(ROOTMANIFEST) := FILEMODE = 0444
+
+#install rules
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+ypupdated_prot.h: ypupdate_prot.x
+ $(RM) ypupdated_prot.h; $(RPCGEN) -C -h ypupdate_prot.x -o ypupdated_prot.h
+
+$(RPCYPUPDATEOBJ): ypupdated_prot.h
+
+rpc.ypupdated: $(RPCYPUPDATEOBJ)
+ $(LINK.c) -o $@ $(RPCYPUPDATEOBJ) $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTDIRS) $(IBINPROG) $(INETYPPROG) $(ROOTMANIFEST)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+$(NETYP)/%: %
+ $(INS.file)
+
+clean:
+ $(RM) $(OBJS)
+
+lint:
+ ${LINT.c} ${SRCS}
+
+check: $(CHKMANIFEST)
+
+cstyle:
+ ${CSTYLE} ${SRCS}
+
+# include library targets
+include ../../Makefile.targ
diff --git a/usr/src/cmd/ypcmd/ypupdated/openchild.c b/usr/src/cmd/ypcmd/ypupdated/openchild.c
new file mode 100644
index 0000000000..b83e1fead2
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypupdated/openchild.c
@@ -0,0 +1,152 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if !defined(lint) && defined(SCCSIDS)
+static char sccsid[] = "%Z%%M% %I% %E% SMI";
+#endif
+
+/*
+ * openchild.c
+ *
+ * Open two pipes to a child process, one for reading, one for writing.
+ * The pipes are accessed by FILE pointers. This is NOT a public
+ * interface, but for internal use only!
+ */
+#include <stdio.h>
+
+extern void *malloc();
+extern char *strrchr();
+
+static char *basename();
+static char SHELL[] = "/bin/sh";
+
+extern int close();
+extern int dup();
+extern int execl();
+extern void exit();
+extern long fork();
+extern int pipe();
+extern unsigned int strlen();
+
+/*
+ * returns pid, or -1 for failure
+ */
+_openchild(command, fto, ffrom)
+ char *command;
+ FILE **fto;
+ FILE **ffrom;
+{
+ int i;
+ int pid;
+ int pdto[2];
+ int pdfrom[2];
+ char *com;
+
+
+ if (pipe(pdto) < 0) {
+ goto error1;
+ }
+ if (pipe(pdfrom) < 0) {
+ goto error2;
+ }
+ switch (pid = fork()) {
+ case -1:
+ goto error3;
+
+ case 0:
+ /*
+ * child: read from pdto[0], write into pdfrom[1]
+ */
+ (void) close(0);
+ (void) dup(pdto[0]);
+ (void) close(1);
+ (void) dup(pdfrom[1]);
+
+ /*
+ * adding this closelog for bug id 1238429
+ */
+ closelog();
+ closefrom(3);
+
+ com = malloc((unsigned)strlen(command) + 6);
+ if (com == NULL) {
+ exit(1);
+ }
+ (void) sprintf(com, "exec %s", command);
+ execl(SHELL, basename(SHELL), "-c", com, NULL);
+ exit(1);
+
+ default:
+ /*
+ * parent: write into pdto[1], read from pdfrom[0]
+ */
+ *fto = fdopen(pdto[1], "w");
+ (void) close(pdto[0]);
+ *ffrom = fdopen(pdfrom[0], "r");
+ (void) close(pdfrom[1]);
+ break;
+ }
+ return (pid);
+
+ /*
+ * error cleanup and return
+ */
+error3:
+printf("openchild: error3");
+ (void) close(pdfrom[0]);
+ (void) close(pdfrom[1]);
+error2:
+printf("openchild: error2");
+ (void) close(pdto[0]);
+ (void) close(pdto[1]);
+error1:
+printf("openchild: error1");
+ return (-1);
+}
+
+static char *
+basename(path)
+ char *path;
+{
+ char *p;
+
+ p = strrchr(path, '/');
+ if (p == NULL) {
+ return (path);
+ } else {
+ return (p + 1);
+ }
+}
diff --git a/usr/src/cmd/ypcmd/ypupdated/rpc.ypupdated.c b/usr/src/cmd/ypcmd/ypupdated/rpc.ypupdated.c
new file mode 100644
index 0000000000..6eeec93bd8
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypupdated/rpc.ypupdated.c
@@ -0,0 +1,388 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * NIS update service
+ */
+#include <stdio.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <ctype.h>
+#include <rpc/rpc.h>
+#include <rpc/auth_des.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/termio.h>
+#include <strings.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#include <netdir.h>
+#include <rpcsvc/ypupd.h>
+#include <netdb.h>
+#include "shim.h"
+#include "yptol.h"
+
+#define RPC_INETDSOCK 0 /* socket descriptor if using inetd */
+#define debug(msg) /* turn off debugging */
+
+char YPDIR[] = "/var/yp";
+char UPDATEFILE[] = "updaters";
+
+void ypupdate_prog();
+void detachfromtty();
+int insecure;
+extern SVCXPRT *svctcp_create(int, uint_t, uint_t);
+extern SVCXPRT *svcudp_create();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *cmd;
+ static int issock();
+ int connmaxrec = RPC_MAXDATASIZE;
+ struct stat filestat;
+
+ /*
+ * Check if we are running in N2L mode. If so updated is unsuported.
+ * This could be done by calling is_yptol_mode(), from libnisdb, but it
+ * seems over complex to pull in an entire library for one check so
+ * do it in line. Just pull in the name of file to check.
+ */
+ if (stat(NTOL_MAP_FILE, &filestat) != -1) {
+ fprintf(stderr, "rpc.updated not supported in NIS to LDAP "
+ "transition mode.");
+ exit(1);
+ }
+
+
+ cmd = argv[0];
+ switch (argc) {
+ case 0:
+ cmd = "ypupdated";
+ break;
+ case 1:
+ break;
+ case 2:
+ if (strcmp(argv[1], "-i") == 0) {
+ insecure++;
+ break;
+ } else if (strcmp(argv[1], "-s") == 0) {
+ insecure = 0;
+ break;
+ }
+ default:
+ fprintf(stderr, "%s: warning -- options ignored\n", cmd);
+ break;
+ }
+
+ if (chdir(YPDIR) < 0) {
+ fprintf(stderr, "%s: can't chdir to ", cmd);
+ perror(YPDIR);
+ exit(1);
+ }
+
+ /*
+ * Set non-blocking mode and maximum record size for
+ * connection oriented RPC transports.
+ */
+ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
+ fprintf(stderr, "unable to set maximum RPC record size");
+ }
+
+ if (issock(RPC_INETDSOCK)) {
+ SVCXPRT *transp;
+ int proto = 0;
+ transp = svctcp_create(RPC_INETDSOCK, 0, 0);
+ if (transp == NULL) {
+ fprintf(stderr, "%s: cannot create tcp service\n", cmd);
+ exit(1);
+ }
+ if (!svc_register(transp, YPU_PROG, YPU_VERS, ypupdate_prog,
+ proto)) {
+ fprintf(stderr, "%s: couldn't register service\n", cmd);
+ exit(1);
+ }
+ } else {
+ detachfromtty();
+ (void) rpcb_unset(YPU_PROG, YPU_VERS, 0);
+ if (!svc_create(ypupdate_prog, YPU_PROG, YPU_VERS, "tcp")) {
+ fprintf(stderr, "%s: cannot create tcp service\n", cmd);
+ exit(1);
+ }
+ }
+
+ if (!svc_create(ypupdate_prog, YPU_PROG, YPU_VERS, "udp")) {
+ fprintf(stderr, "%s: cannot create udp service\n", cmd);
+ exit(1);
+ }
+
+ svc_run();
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Determine if a descriptor belongs to a socket or not
+ */
+static int
+issock(fd)
+ int fd;
+{
+ struct stat st;
+
+ if (fstat(fd, &st) == -1)
+ return (0);
+ else
+ return (S_ISSOCK(fd));
+}
+
+
+void
+detachfromtty()
+{
+ int tt;
+
+ close(0);
+ close(1);
+ close(2);
+ switch (fork()) {
+ case -1:
+ perror("fork");
+ break;
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
+ tt = open("/dev/tty", O_RDWR, 0);
+ if (tt >= 0) {
+ ioctl(tt, TIOCNOTTY, 0);
+ close(tt);
+ }
+ open("/dev/null", O_RDWR, 0);
+ dup(0);
+ dup(0);
+}
+
+void
+ypupdate_prog(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ struct ypupdate_args args;
+ uint_t rslt;
+ uint_t op;
+ char *netname;
+ char namebuf[MAXNETNAMELEN+1];
+ struct authunix_parms *aup;
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ svc_sendreply(transp, xdr_void, NULL);
+ return;
+ case YPU_CHANGE:
+ op = YPOP_CHANGE;
+ break;
+ case YPU_DELETE:
+ op = YPOP_DELETE;
+ break;
+ case YPU_INSERT:
+ op = YPOP_INSERT;
+ break;
+ case YPU_STORE:
+ op = YPOP_STORE;
+ break;
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_DES:
+ netname = ((struct authdes_cred *)
+ rqstp->rq_clntcred)->adc_fullname.name;
+ break;
+ case AUTH_UNIX:
+ if (insecure) {
+ aup = (struct authunix_parms *)rqstp->rq_clntcred;
+ if (aup->aup_uid == 0) {
+ /*
+ * addr2netname(namebuf, svc_getcaller(transp));
+ */
+ addr2netname(namebuf, transp);
+ } else {
+ user2netname(namebuf, aup->aup_uid, NULL);
+ }
+ netname = namebuf;
+ break;
+ }
+ default:
+ svcerr_weakauth(transp);
+ return;
+ }
+ bzero(&args, sizeof (args));
+ if (!svc_getargs(transp, xdr_ypupdate_args, (caddr_t)&args)) {
+ svcerr_decode(transp);
+ return;
+ }
+ rslt = update(netname,
+ args.mapname, op, args.key.yp_buf_len, args.key.yp_buf_val,
+ args.datum.yp_buf_len, args.datum.yp_buf_val);
+ if (!svc_sendreply(transp, xdr_u_int, (const caddr_t)&rslt)) {
+ debug("svc_sendreply failed");
+ }
+ if (!svc_freeargs(transp, xdr_ypupdate_args, (caddr_t)&args)) {
+ debug("svc_freeargs failed");
+ }
+}
+
+/*
+ * Determine if requester is allowed to update the given map,
+ * and update it if so. Returns the NIS status, which is zero
+ * if there is no access violation.
+ */
+update(requester, mapname, op, keylen, key, datalen, data)
+ char *requester;
+ char *mapname;
+ uint_t op;
+ uint_t keylen;
+ char *key;
+ uint_t datalen;
+ char *data;
+{
+ char updater[MAXMAPNAMELEN + 40];
+ FILE *childargs;
+ FILE *childrslt;
+ int status;
+ int yperrno;
+ int pid;
+ char default_domain[YPMAXDOMAIN];
+ int err;
+ char fake_key[10];
+ char *outval = NULL;
+ int outval_len;
+
+ if (getdomainname(default_domain, YPMAXDOMAIN)) {
+ debug("Couldn't get default domain name");
+ return (YPERR_YPERR);
+ }
+
+ /* check to see if we have a valid mapname */
+ strncpy(fake_key, "junk", 4);
+ err = yp_match(default_domain, mapname,
+ fake_key, strlen(fake_key), &outval, &outval_len);
+ switch (err) {
+ case YPERR_MAP:
+ return (YPERR_YPERR);
+ break;
+ default:
+ /* do nothing, only worry about above return code */
+ break;
+ }
+
+ /* valid map - continue */
+ sprintf(updater, "make -s -f %s %s", UPDATEFILE, mapname);
+ pid = _openchild(updater, &childargs, &childrslt);
+ if (pid < 0) {
+ debug("openpipes failed");
+ return (YPERR_YPERR);
+ }
+
+ /*
+ * Write to child
+ */
+ fprintf(childargs, "%s\n", requester);
+ fprintf(childargs, "%u\n", op);
+ fprintf(childargs, "%u\n", keylen);
+ fwrite(key, keylen, 1, childargs);
+ fprintf(childargs, "\n");
+ fprintf(childargs, "%u\n", datalen);
+ fwrite(data, datalen, 1, childargs);
+ fprintf(childargs, "\n");
+ fclose(childargs);
+
+ /*
+ * Read from child
+ */
+ fscanf(childrslt, "%d", &yperrno);
+ fclose(childrslt);
+
+ wait(&status);
+ if (!WIFEXITED(status)) {
+ return (YPERR_YPERR);
+ }
+ return (yperrno);
+}
+
+#if 0
+addr2netname(namebuf, addr)
+ char *namebuf;
+ struct sockaddr_in *addr;
+{
+ struct hostent *h;
+
+ h = gethostbyaddr((const char *) &addr->sin_addr,
+ sizeof (addr->sin_addr), AF_INET);
+ if (h == NULL) {
+ host2netname(namebuf, (const char *) inet_ntoa(addr->sin_addr),
+ NULL);
+ } else {
+ host2netname(namebuf, h->h_name, NULL);
+ }
+}
+#endif
+
+
+static int
+addr2netname(namebuf, transp)
+ char *namebuf;
+ SVCXPRT *transp;
+{
+ struct nd_hostservlist *hostservs = NULL;
+ struct netconfig *nconf;
+ struct netbuf *who;
+
+ who = svc_getrpccaller(transp);
+ if ((who == NULL) || (who->len == 0))
+ return (-1);
+ if ((nconf = getnetconfigent(transp->xp_netid))
+ == (struct netconfig *)NULL)
+ return (-1);
+ if (netdir_getbyaddr(nconf, &hostservs, who) != 0) {
+ (void) freenetconfigent(nconf);
+ return (-1);
+ }
+ if (hostservs != NULL)
+ strcpy(namebuf, hostservs->h_hostservs->h_host);
+
+ (void) freenetconfigent(nconf);
+ netdir_free((char *)hostservs, ND_HOSTSERVLIST);
+ return (0);
+}
diff --git a/usr/src/cmd/ypcmd/ypupdated/update.xml b/usr/src/cmd/ypcmd/ypupdated/update.xml
new file mode 100644
index 0000000000..0515239573
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypupdated/update.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWypr:update'>
+
+<service
+ name='network/nis/update'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <dependency
+ name='fs'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <dependency
+ name='rpcbind'
+ grouping='require_all'
+ restart_on='restart'
+ type='service'>
+ <service_fmri value='svc:/network/rpc/bind' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/lib/netsvc/yp/rpc.ypupdated'
+ timeout_seconds='300' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='30' />
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ NIS (YP) update daemon
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='rpc.ypupdated' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/ypcmd/ypupdated/ypupdate_prot.x b/usr/src/cmd/ypcmd/ypupdated/ypupdate_prot.x
new file mode 100644
index 0000000000..0561e9becb
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypupdated/ypupdate_prot.x
@@ -0,0 +1,62 @@
+%/*
+% * CDDL HEADER START
+% *
+% * The contents of this file are subject to the terms of the
+% * Common Development and Distribution License, Version 1.0 only
+% * (the "License"). You may not use this file except in compliance
+% * with the License.
+% *
+% * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% * or http://www.opensolaris.org/os/licensing.
+% * See the License for the specific language governing permissions
+% * and limitations under the License.
+% *
+% * When distributing Covered Code, include this CDDL HEADER in each
+% * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% * If applicable, add the following below this CDDL HEADER, with the
+% * fields enclosed by brackets "[]" replaced with your own identifying
+% * information: Portions Copyright [yyyy] [name of copyright owner]
+% *
+% * CDDL HEADER END
+% *
+% * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+% * Use is subject to license terms.
+% */
+%
+%#pragma ident "%Z%%M% %I% %E% SMI"
+%
+%/*
+% * Compiled from ypupdate_prot.x using rpcgen
+% * This is NOT source code!
+% * DO NOT EDIT THIS FILE!
+% */
+
+/*
+ * NIS update service protocol
+ */
+const MAXMAPNAMELEN = 255;
+const MAXYPDATALEN = 1023;
+const MAXERRMSGLEN = 255;
+
+program YPU_PROG {
+ version YPU_VERS {
+ u_int YPU_CHANGE(ypupdateargs) = 1;
+ u_int YPU_INSERT(ypupdateargs) = 2;
+ u_int YPU_DELETE(ypdeleteargs) = 3;
+ u_int YPU_STORE(ypupdateargs) = 4;
+ } = 1;
+} = 100028;
+
+typedef opaque yp_buf<MAXYPDATALEN>;
+
+struct ypupdate_args {
+ string mapname<MAXMAPNAMELEN>;
+ yp_buf key;
+ yp_buf datum;
+};
+
+struct ypdelete_args {
+ string mapname<MAXMAPNAMELEN>;
+ yp_buf key;
+};
+
diff --git a/usr/src/cmd/ypcmd/ypv1_prot.h b/usr/src/cmd/ypcmd/ypv1_prot.h
new file mode 100644
index 0000000000..f8bb36674a
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypv1_prot.h
@@ -0,0 +1,145 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990 Sun Microsystems, Inc.
+ */
+
+#ifndef __YPV1_PROT_H
+#define __YPV1_PROT_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This contains symbol and structure definitions used in supporting the old
+ * "v1" protocol. They were previously defined in yp_prot.h.
+ *
+ * This file exists so that the NIS system can provide backward compatibility.
+ * Normal NIS client processes should not use this interface: the old
+ * protocol will not be supported in the next release.
+ */
+#define YPOLDVERS (YPVERS - 1)
+#define YPOLDPROC_NULL ((u_long)0)
+#define YPOLDPROC_DOMAIN ((u_long)1)
+#define YPOLDPROC_DOMAIN_NONACK ((u_long)2)
+#define YPOLDPROC_MATCH ((u_long)3)
+#define YPOLDPROC_FIRST ((u_long)4)
+#define YPOLDPROC_NEXT ((u_long)5)
+#define YPOLDPROC_POLL ((u_long)6)
+#define YPOLDPROC_PUSH ((u_long)7)
+#define YPOLDPROC_PULL ((u_long)8)
+#define YPOLDPROC_GET ((u_long)9)
+
+#define YPMATCH_REQTYPE YPREQ_KEY
+#define ypmatch_req_domain yp_reqbody.yp_req_keytype.domain
+#define ypmatch_req_map yp_reqbody.yp_req_keytype.map
+#define ypmatch_req_keydat yp_reqbody.yp_req_keytype.keydat
+#define ypmatch_req_keyptr yp_reqbody.yp_req_keytype.keydat.dptr
+#define ypmatch_req_keysize yp_reqbody.yp_req_keytype.keydat.dsize
+
+#define YPFIRST_REQTYPE YPREQ_NOKEY
+#define ypfirst_req_domain yp_reqbody.yp_req_nokeytype.domain
+#define ypfirst_req_map yp_reqbody.yp_req_nokeytype.map
+
+#define YPNEXT_REQTYPE YPREQ_KEY
+#define ypnext_req_domain yp_reqbody.yp_req_keytype.domain
+#define ypnext_req_map yp_reqbody.yp_req_keytype.map
+#define ypnext_req_keydat yp_reqbody.yp_req_keytype.keydat
+#define ypnext_req_keyptr yp_reqbody.yp_req_keytype.keydat.dptr
+#define ypnext_req_keysize yp_reqbody.yp_req_keytype.keydat.dsize
+
+#define YPPUSH_REQTYPE YPREQ_NOKEY
+#define yppush_req_domain yp_reqbody.yp_req_nokeytype.domain
+#define yppush_req_map yp_reqbody.yp_req_nokeytype.map
+
+#define YPPULL_REQTYPE YPREQ_NOKEY
+#define yppull_req_domain yp_reqbody.yp_req_nokeytype.domain
+#define yppull_req_map yp_reqbody.yp_req_nokeytype.map
+
+#define YPPOLL_REQTYPE YPREQ_NOKEY
+#define yppoll_req_domain yp_reqbody.yp_req_nokeytype.domain
+#define yppoll_req_map yp_reqbody.yp_req_nokeytype.map
+
+#define YPGET_REQTYPE YPREQ_MAP_PARMS
+#define ypget_req_domain yp_reqbody.yp_req_map_parmstype.domain
+#define ypget_req_map yp_reqbody.yp_req_map_parmstype.map
+#define ypget_req_ordernum yp_reqbody.yp_req_map_parmstype.ordernum
+#define ypget_req_owner yp_reqbody.yp_req_map_parmstype.owner
+
+#define YPMATCH_RESPTYPE YPRESP_VAL
+#define ypmatch_resp_status yp_respbody.yp_resp_valtype.status
+#define ypmatch_resp_valdat yp_respbody.yp_resp_valtype.valdat
+#define ypmatch_resp_valptr yp_respbody.yp_resp_valtype.valdat.dptr
+#define ypmatch_resp_valsize yp_respbody.yp_resp_valtype.valdat.dsize
+
+#define YPFIRST_RESPTYPE YPRESP_KEY_VAL
+#define ypfirst_resp_status yp_respbody.yp_resp_key_valtype.status
+#define ypfirst_resp_keydat yp_respbody.yp_resp_key_valtype.keydat
+#define ypfirst_resp_keyptr yp_respbody.yp_resp_key_valtype.keydat.dptr
+#define ypfirst_resp_keysize yp_respbody.yp_resp_key_valtype.keydat.dsize
+#define ypfirst_resp_valdat yp_respbody.yp_resp_key_valtype.valdat
+#define ypfirst_resp_valptr yp_respbody.yp_resp_key_valtype.valdat.dptr
+#define ypfirst_resp_valsize yp_respbody.yp_resp_key_valtype.valdat.dsize
+
+#define YPNEXT_RESPTYPE YPRESP_KEY_VAL
+#define ypnext_resp_status yp_respbody.yp_resp_key_valtype.status
+#define ypnext_resp_keydat yp_respbody.yp_resp_key_valtype.keydat
+#define ypnext_resp_keyptr yp_respbody.yp_resp_key_valtype.keydat.dptr
+#define ypnext_resp_keysize yp_respbody.yp_resp_key_valtype.keydat.dsize
+#define ypnext_resp_valdat yp_respbody.yp_resp_key_valtype.valdat
+#define ypnext_resp_valptr yp_respbody.yp_resp_key_valtype.valdat.dptr
+#define ypnext_resp_valsize yp_respbody.yp_resp_key_valtype.valdat.dsize
+
+#define YPPOLL_RESPTYPE YPRESP_MAP_PARMS
+#define yppoll_resp_domain yp_respbody.yp_resp_map_parmstype.domain
+#define yppoll_resp_map yp_respbody.yp_resp_map_parmstype.map
+#define yppoll_resp_ordernum yp_respbody.yp_resp_map_parmstype.ordernum
+#define yppoll_resp_owner yp_respbody.yp_resp_map_parmstype.owner
+
+
+extern bool _xdr_yprequest();
+extern bool _xdr_ypresponse();
+
+/* XXX - excess baggage? - georgn */
+#if 0
+#define YPBINDOLDVERS (YPBINDVERS - 1)
+struct ypbind_oldsetdom {
+ char ypoldsetdom_domain[YPMAXDOMAIN + 1];
+ struct ypbind_binding {
+ opaque ypbind_binding_addr[4]; /* In network order */
+ opaque ypbind_binding_port[2]; /* In network order */
+ } ypoldsetdom_binding;
+};
+#define ypoldsetdom_addr ypoldsetdom_binding.ypbind_binding_addr
+#define ypoldsetdom_port ypoldsetdom_binding.ypbind_binding_port
+#endif
+
+extern bool _xdr_ypbind_oldsetdom();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __YPV1_PROT_H */
diff --git a/usr/src/cmd/ypcmd/ypv1_xdr.c b/usr/src/cmd/ypcmd/ypv1_xdr.c
new file mode 100644
index 0000000000..5fa139febe
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypv1_xdr.c
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+#ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 1995 Sun Microsystems, Inc
+ * All rights reserved.
+ */
+
+/*
+ * This contains the xdr functions needed by ypserv and the NIS
+ * administrative tools to support the previous version of the NIS protocol.
+ * Note that many "old" xdr functions are called, with the assumption that
+ * they have not changed between the v1 protocol (which this module exists
+ * to support) and the current v2 protocol.
+ */
+
+#define NULL 0
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include "ypv1_prot.h"
+#include <rpcsvc/ypclnt.h>
+typedef struct xdr_discrim XDR_DISCRIM;
+
+extern bool xdr_ypreq_key();
+extern bool xdr_ypreq_nokey();
+extern bool xdr_ypresp_val();
+extern bool xdr_ypresp_key_val();
+extern bool xdr_ypmap_parms();
+
+
+/*
+ * Serializes/deserializes a yprequest structure.
+ */
+bool
+_xdr_yprequest(XDR *xdrs, struct yprequest *ps)
+{
+ XDR_DISCRIM yprequest_arms[4];
+
+ yprequest_arms[0].value = (int)YPREQ_KEY;
+ yprequest_arms[1].value = (int)YPREQ_NOKEY;
+ yprequest_arms[2].value = (int)YPREQ_KEY;
+ yprequest_arms[3].value = __dontcare__;
+ yprequest_arms[0].proc = (xdrproc_t)xdr_ypreq_key;
+ yprequest_arms[1].proc = (xdrproc_t)xdr_ypreq_nokey;
+ yprequest_arms[2].proc = (xdrproc_t)xdr_ypmap_parms;
+ yprequest_arms[3].proc = (xdrproc_t)NULL;
+
+ return (xdr_union(xdrs,
+ (int *) &ps->yp_reqtype,
+ (char *) &ps->yp_reqbody,
+ yprequest_arms, NULL));
+}
+
+/*
+ * Serializes/deserializes a ypresponse structure.
+ */
+bool
+_xdr_ypresponse(XDR *xdrs, struct ypresponse *ps)
+{
+ XDR_DISCRIM ypresponse_arms[4];
+
+ ypresponse_arms[0].value = (int)YPRESP_VAL;
+ ypresponse_arms[1].value = (int)YPRESP_KEY_VAL;
+ ypresponse_arms[2].value = (int)YPRESP_MAP_PARMS;
+ ypresponse_arms[3].value = __dontcare__;
+ ypresponse_arms[0].proc = (xdrproc_t)xdr_ypresp_val;
+ ypresponse_arms[1].proc = (xdrproc_t)xdr_ypresp_key_val;
+ ypresponse_arms[2].proc = (xdrproc_t)xdr_ypmap_parms;
+ ypresponse_arms[3].proc = (xdrproc_t)NULL;
+
+ return (xdr_union(xdrs,
+ (int *) &ps->yp_resptype,
+ (char *) &ps->yp_respbody,
+ ypresponse_arms, NULL));
+}
+
+/* XXX - Excess baggage? - georgn */
+#if 0
+/*
+ * Serializes/deserializes a ypbind_oldsetdom structure.
+ */
+bool
+_xdr_ypbind_oldsetdom(XDR *xdrs, struct ypbind_setdom *ps)
+{
+ char *domain = ps->ypsetdom_domain;
+
+ return (xdr_ypdomain_wrap_string(xdrs, &domain) &&
+ xdr_yp_binding(xdrs, &ps->ypsetdom_binding));
+}
+#endif
diff --git a/usr/src/cmd/ypcmd/ypv2_bind.h b/usr/src/cmd/ypcmd/ypv2_bind.h
new file mode 100644
index 0000000000..928ec4249a
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypv2_bind.h
@@ -0,0 +1,88 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains symbols and structures defining diffences
+ * between Version 3 and Version 2 of the yp bind protocol.
+ */
+
+#include "netinet/in.h"
+
+#define YPBINDOLDVERS ((u_long)2)
+#define YPOLDMAXDOMAIN ((u_long)64)
+
+struct domv2_binding {
+ struct domv2_binding *dom_pnext;
+ char dom_domain[YPMAXDOMAIN + 1];
+ struct sockaddr_in dom_server_addr;
+ unsigned short int dom_server_port;
+ int dom_socket;
+ CLIENT *dom_client;
+ unsigned short int dom_local_port;
+ long int dom_vers;
+};
+
+
+/*
+ * Protocol between clients and yp binder servers
+ */
+
+/*
+ * Response structure and binding info
+ */
+
+struct ypbindv2_binding {
+ struct in_addr ypbind_binding_addr; /* In network order */
+ unsigned short int ypbind_binding_port; /* In network order */
+};
+struct ypbindv2_resp {
+ enum ypbind_resptype ypbind_status;
+ union {
+ unsigned long ypbind_error;
+ struct ypbindv2_binding ypbind_bindinfo;
+ } ypbind_respbody;
+};
+
+/*
+ * Request data structure for ypbind "Set domain" procedure.
+ */
+struct ypbindv2_setdom {
+ char ypsetdom_domain[YPMAXDOMAIN + 1];
+ struct ypbindv2_binding ypsetdom_binding;
+ unsigned short ypsetdom_vers;
+};
+#define ypsetdom_addr ypsetdom_binding.ypbind_binding_addr
+#define ypsetdom_port ypsetdom_binding.ypbind_binding_port
diff --git a/usr/src/cmd/ypcmd/ypwhich.c b/usr/src/cmd/ypcmd/ypwhich.c
new file mode 100644
index 0000000000..77d5624859
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypwhich.c
@@ -0,0 +1,774 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a user command which tells which yp server is being used by a
+ * given machine, or which yp server is the master for a named map.
+ *
+ * Usage is:
+ * ypwhich [-d domain] [-m [mname] [-t] | [-Vn] host]
+ * ypwhich -x
+ * where: the -d switch can be used to specify a domain other than the
+ * default domain. -m tells the master of that map. mname is a mapname
+ * If the -m option is used, ypwhich will act like a vanilla yp client,
+ * and will not attempt to choose a particular yp server. On the
+ * other hand, if no -m switch is used, ypwhich will talk directly to the yp
+ * bind process on the named host, or to the local ypbind process if no host
+ * name is specified. -t switch inhibits nickname translation of map names.
+ * -x is to dump the nickname translation table from file /var/yp/nicknames.
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include "yp_b.h"
+#include "ypv2_bind.h"
+#include <string.h>
+#include <netdir.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <netinet/ip6.h>
+#include <sys/utsname.h>
+
+#define YPSLEEPTIME 5 /* between two tries of bind */
+
+#define TIMEOUT 30 /* Total seconds for timeout */
+#define INTER_TRY 10 /* Seconds between tries */
+
+static int translate = TRUE;
+static int dodump = FALSE;
+static char *domain = NULL;
+static char default_domain_name[YPMAXDOMAIN];
+static char *host = NULL;
+static int vers = YPBINDVERS;
+static char default_host_name[256];
+static bool get_master = FALSE;
+static bool get_server = FALSE;
+static char *map = NULL;
+static char nm[YPMAXMAP+1];
+static struct timeval timeout = {
+ TIMEOUT, /* Seconds */
+ 0 /* Microseconds */
+};
+static char nullstring[] = "\000";
+static char err_usage[] =
+"Usage:\n\
+ ypwhich [-d domain] [[-t] -m [mname] | [-Vn] host]\n\
+ ypwhich -x\n\
+where\n\
+ mname may be either a mapname or a nickname for a map.\n\
+ host if specified, is the machine whose NIS server is to be found.\n\
+ -t inhibits map nickname translation.\n\
+ -Vn version of ypbind, V3 is default.\n\
+ -x dumps the map nickname translation table.\n";
+static char err_bad_args[] =
+"ypwhich: %s argument is bad.\n";
+static char err_cant_get_kname[] =
+"ypwhich: can't get %s back from system call.\n";
+static char err_null_kname[] =
+"ypwhich: the %s hasn't been set on this machine.\n";
+static char err_bad_mapname[] = "mapname";
+static char err_bad_domainname[] = "domainname";
+static char err_bad_hostname[] = "hostname";
+
+static void get_command_line_args();
+static void getdomain();
+static void getlochost();
+static void get_server_name();
+static int call_binder();
+static void get_map_master();
+extern void maketable();
+extern int getmapname();
+#ifdef DEBUG
+static void dump_response();
+#endif
+static void dump_ypmaps();
+static void dumpmaps();
+
+static bool xdr_yp_inaddr ();
+static bool xdr_old_ypbind_resp ();
+static bool xdr_old_yp_binding();
+static int old_call_binder();
+static void print_server();
+
+/* need these for call to (remote) V2 ypbind */
+struct old_ypbind_binding {
+ struct in_addr ypbind_binding_addr; /* In network order */
+ unsigned short int ypbind_binding_port; /* In network order */
+};
+
+struct old_ypbind_resp {
+ enum ypbind_resptype ypbind_status;
+ union {
+ unsigned long ypbind_error;
+ struct old_ypbind_binding ypbind_bindinfo;
+ } ypbind_respbody;
+};
+
+/*
+ * This is the main line for the ypwhich process.
+ */
+main(argc, argv)
+char **argv;
+{
+ get_command_line_args(argc, argv);
+
+ if (dodump) {
+ maketable(dodump);
+ exit(0);
+ }
+
+ if (!domain) {
+ getdomain();
+ }
+
+ if (map && translate && (strchr(map, '.') == NULL) &&
+ (getmapname(map, nm))) {
+ map = nm;
+ }
+
+ if (get_server) {
+ if (!host)
+ getlochost();
+ get_server_name();
+ } else {
+ if (map)
+ get_map_master();
+ else
+ dump_ypmaps();
+ }
+
+ return (0);
+}
+
+/*
+ * This does the command line argument processing.
+ */
+static void
+get_command_line_args(argc, argv)
+int argc;
+char **argv;
+
+{
+ argv++;
+
+ if (argc == 1) {
+ get_server = TRUE;
+ return;
+ }
+
+ while (--argc) {
+
+ if ((*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+
+ case 'V':
+
+ vers = atoi(argv[0]+2);
+ if (vers < 1) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+ argv++;
+ break;
+
+ case 'm':
+ get_master = TRUE;
+ argv++;
+
+ if (argc > 1) {
+
+ if ((*(argv))[0] == '-') {
+ break;
+ }
+
+ argc--;
+ map = *argv;
+ argv++;
+
+ if ((int)strlen(map) > YPMAXMAP) {
+ (void) fprintf(stderr, err_bad_args,
+ err_bad_mapname);
+ exit(1);
+ }
+
+ }
+
+ break;
+
+ case 'd':
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+ argv++;
+
+ if ((int)strlen(domain) > YPMAXDOMAIN) {
+ (void) fprintf(stderr, err_bad_args,
+ err_bad_domainname);
+ exit(1);
+ }
+
+ } else {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ break;
+
+ case 't':
+ translate = FALSE;
+ argv++;
+ break;
+
+ case 'x':
+ dodump = TRUE;
+ argv++;
+ break;
+
+ default:
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ } else {
+
+ if (get_server) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ get_server = TRUE;
+ host = *argv;
+ argv++;
+
+ if ((int)strlen(host) > 256) {
+ (void) fprintf(stderr,
+ err_bad_args, err_bad_hostname);
+ exit(1);
+ }
+ }
+ }
+
+ if (get_master && get_server) {
+ (void) fprintf(stderr, err_usage);
+ exit(1);
+ }
+
+ if (!get_master && !get_server) {
+ get_server = TRUE;
+ }
+}
+
+/*
+ * This gets the local default domainname, and makes sure that it's set
+ * to something reasonable. domain is set here.
+ */
+static void
+getdomain()
+{
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ (void) fprintf(stderr, err_cant_get_kname, err_bad_domainname);
+ exit(1);
+ }
+
+ if ((int)strlen(domain) == 0) {
+ (void) fprintf(stderr, err_null_kname, err_bad_domainname);
+ exit(1);
+ }
+}
+
+/*
+ * This gets the local hostname back from the kernel
+ */
+static void
+getlochost()
+{
+ struct utsname utsname;
+
+ if (uname(&utsname) != -1) {
+ strcpy(default_host_name, utsname.nodename);
+ host = default_host_name;
+ } else {
+ (void) fprintf(stderr, err_cant_get_kname, err_bad_hostname);
+ exit(1);
+ }
+
+}
+
+/*
+ * This tries to find the name of the server to which the binder in question
+ * is bound. If one of the -Vx flags was specified, it will try only for
+ * that protocol version, otherwise, it will start with the current version,
+ * then drop back to the previous version.
+ */
+static void
+get_server_name()
+{
+ char *notbound = "Domain %s not bound on %s.\n";
+
+ if (vers >= 3){
+ if (!call_binder(vers))
+ (void) fprintf(stderr, notbound, domain, host);
+ } else {
+ if (!old_call_binder(vers))
+ (void) fprintf(stderr, notbound, domain, host);
+ }
+}
+
+extern CLIENT *__clnt_create_loopback();
+
+/*
+ * This sends a message to the ypbind process on the node with
+ * the host name
+ */
+static int
+call_binder(vers)
+int vers;
+{
+ CLIENT *client;
+ struct ypbind_resp *response;
+ struct ypbind_domain ypbd;
+ char errstring[256];
+ extern struct rpc_createerr rpc_createerr;
+ int yperr = 0;
+ struct utsname utsname;
+ const char *str;
+
+ /*
+ * CAUTION: Do not go to NIS if the host is the same as the local host
+ * XXX: Lots of special magic to distinguish between local and remote
+ * case. We want to make sure the local case doesn't hang.
+ */
+
+ if ((uname(&utsname) != -1) &&
+ (strcmp(host, utsname.nodename) == 0))
+ client = __clnt_create_loopback(YPBINDPROG, vers, &yperr);
+ else
+ client = clnt_create(host, YPBINDPROG, vers, "netpath");
+ if (client == NULL) {
+ if (yperr)
+ (void) fprintf(stderr,
+ "ypwhich: %s\n", yperr_string(yperr));
+ else {
+ if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED ||
+ rpc_createerr.cf_stat == RPC_PROGUNAVAIL) {
+ (void) fprintf(stderr,
+ "ypwhich: %s is not running ypbind\n", host);
+ } else if (rpc_createerr.cf_stat == RPC_PMAPFAILURE) {
+ (void) fprintf(stderr,
+ "ypwhich: %s is not running rpcbind\n",
+ host);
+ } else
+ (void) clnt_pcreateerror("ypwhich: \
+clnt_create error");
+ }
+ exit(1);
+ }
+ ypbd.ypbind_domainname = domain;
+ ypbd.ypbind_vers = vers;
+ response = ypbindproc_domain_3(&ypbd, client);
+
+ if (response == NULL){
+ (void) sprintf(errstring,
+ "ypwhich: can't call ypbind on %s", host);
+ (void) clnt_perror(client, errstring);
+ exit(1);
+ }
+
+ clnt_destroy(client);
+
+ if (response->ypbind_status != YPBIND_SUCC_VAL) {
+ return (FALSE);
+ }
+
+ if (response->ypbind_resp_u.ypbind_bindinfo) {
+ char *server =
+ response->ypbind_resp_u.ypbind_bindinfo->ypbind_servername;
+
+ if (strcmp(server, nullstring) == 0) {
+ /* depends on a hack in ypbind */
+ struct nd_hostservlist *nhs = NULL;
+ struct netconfig *nconf =
+ response->ypbind_resp_u.ypbind_bindinfo->ypbind_nconf;
+ struct netbuf *svcaddr =
+ response->ypbind_resp_u.ypbind_bindinfo->ypbind_svcaddr;
+
+ if (netdir_getbyaddr(nconf, &nhs, svcaddr) != ND_OK) {
+ struct sockaddr_in *sa4;
+ struct sockaddr_in6 *sa6;
+ char buf[INET6_ADDRSTRLEN];
+ char xbuf[IPV6_ADDR_LEN];
+ int af;
+ void *addr;
+ XDR xdrs;
+
+ sa4 = (struct sockaddr_in *)svcaddr->buf;
+ af = ntohs(sa4->sin_family);
+ if (af != sa4->sin_family) {
+ xdrmem_create(&xdrs,
+ (caddr_t)xbuf, IPV6_ADDR_LEN,
+ XDR_DECODE);
+ if (af == AF_INET6) {
+ xdr_opaque(&xdrs,
+ (caddr_t)svcaddr->buf,
+ IPV6_ADDR_LEN);
+ sa6 = (struct sockaddr_in6 *)
+ xbuf;
+ addr = &sa6->sin6_addr;
+ } else {
+ xdr_opaque(&xdrs,
+ (caddr_t)svcaddr->buf,
+ IPV4_ADDR_LEN);
+ sa4 = (struct sockaddr_in *)
+ xbuf;
+ addr = &sa4->sin_addr;
+ }
+ } else {
+ if (af == AF_INET6) {
+ sa6 = (struct sockaddr_in6 *)
+ svcaddr->buf;
+ addr = &sa6->sin6_addr;
+ } else {
+ addr = &sa4->sin_addr;
+ }
+ }
+ str = inet_ntop(af, addr, buf, sizeof (buf));
+ if (str == NULL)
+ perror("inet_ntop");
+ else
+ fprintf(stdout, "%s\n", str);
+ } else {
+ str = nhs->h_hostservs->h_host;
+ if (str == NULL)
+ str = "<unknown>";
+ fprintf(stdout, "%s\n", str);
+ }
+ netdir_free((char *)nhs, ND_HOSTSERVLIST);
+ } else {
+ fprintf(stdout, "%s\n", server);
+ }
+ }
+#ifdef DEBUG
+ dump_response(response);
+#endif
+ return (TRUE);
+}
+
+/*
+ * Serializes/deserializes an in_addr struct.
+ *
+ * Note: There is a data coupling between the "definition" of a struct
+ * in_addr implicit in this xdr routine, and the true data definition in
+ * <netinet/in.h>.
+ */
+static bool xdr_yp_inaddr(xdrs, ps)
+ XDR * xdrs;
+ struct in_addr *ps;
+
+{
+ return (xdr_opaque(xdrs, (caddr_t)&ps->s_addr, 4));
+}
+
+/*
+ * Serializes/deserializes an old ypbind_binding struct.
+ */
+static bool xdr_old_yp_binding(xdrs, ps)
+ XDR * xdrs;
+ struct old_ypbind_binding *ps;
+
+{
+ return (xdr_yp_inaddr(xdrs, &ps->ypbind_binding_addr) &&
+ xdr_opaque(xdrs, (caddr_t)&ps->ypbind_binding_port, 2));
+}
+
+/*
+ * Serializes/deserializes a ypbind_resp structure.
+ */
+static bool xdr_old_ypbind_resp(xdrs, ps)
+ XDR * xdrs;
+ struct old_ypbind_resp *ps;
+
+{
+ if (!xdr_enum(xdrs, (enum_t*)&ps->ypbind_status)) {
+ return (FALSE);
+ }
+ switch (ps->ypbind_status) {
+ case YPBIND_SUCC_VAL:
+ return (xdr_old_yp_binding(xdrs,
+ &ps->ypbind_respbody.ypbind_bindinfo));
+ case YPBIND_FAIL_VAL:
+ return (xdr_u_long(xdrs,
+ &ps->ypbind_respbody.ypbind_error));
+ }
+ return (FALSE);
+}
+/* This sends a message to the old ypbind process on host. */
+static int old_call_binder(vers)
+ int vers;
+{
+ CLIENT *client;
+ struct hostent *hp;
+ int sock = RPC_ANYSOCK;
+ enum clnt_stat rpc_stat;
+ struct old_ypbind_resp response;
+ char errstring[256];
+ extern struct rpc_createerr rpc_createerr;
+ struct in_addr *server;
+
+ if ((client = clnt_create(host, YPBINDPROG, vers, "udp")) == NULL) {
+ if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) {
+ (void) printf("ypwhich: %s is not running ypbind\n",
+ host);
+ exit(1);
+ }
+ if (rpc_createerr.cf_stat == RPC_PMAPFAILURE) {
+ (void) printf("ypwhich: %s is not running port mapper\n",
+ host);
+ exit(1);
+ }
+ (void) clnt_pcreateerror("ypwhich: clnt_create error");
+ exit(1);
+ }
+
+ rpc_stat = clnt_call(client, YPBINDPROC_DOMAIN,
+ (xdrproc_t)xdr_ypdomain_wrap_string, (caddr_t)&domain,
+ (xdrproc_t)xdr_old_ypbind_resp, (caddr_t)&response,
+ timeout);
+
+ if ((rpc_stat != RPC_SUCCESS) &&
+ (rpc_stat != RPC_PROGVERSMISMATCH)) {
+ (void) sprintf(errstring,
+ "ypwhich: can't call ypbind on %s", host);
+ (void) clnt_perror(client, errstring);
+ exit(1);
+ }
+
+ clnt_destroy(client);
+ close(sock);
+
+ if ((rpc_stat != RPC_SUCCESS) ||
+ (response.ypbind_status != YPBIND_SUCC_VAL)) {
+ return (FALSE);
+ }
+
+ server = &response.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr;
+ print_server (server);
+
+ return (TRUE);
+}
+
+/*
+ * For old version:
+ * This translates a server address to a name and prints it.
+ * We'll get a name by using the standard library routine.
+ */
+static void print_server(server)
+ struct in_addr *server;
+{
+ char buf[256];
+ struct hostent *hp;
+
+ strcpy(buf, inet_ntoa(*server));
+ hp = gethostbyaddr((char*)&server->s_addr,
+ sizeof (struct in_addr), AF_INET);
+
+ printf("%s\n", hp ? hp->h_name : buf);
+}
+
+#ifdef DEBUG
+static void
+dump_response(which)
+ypbind_resp * which;
+{
+ struct netconfig *nc;
+ struct netbuf *ua;
+ ypbind_binding * b;
+
+ int i;
+
+ {
+ b = which->ypbind_resp_u.ypbind_bindinfo;
+ if (b == NULL)
+ (void) fprintf(stderr, "???NO Binding information\n");
+ else {
+ (void) fprintf(stderr,
+ "server=%s lovers=%ld hivers=%ld\n",
+ b->ypbind_servername,
+ b->ypbind_lo_vers, b->ypbind_hi_vers);
+ nc = b->ypbind_nconf;
+ ua = b->ypbind_svcaddr;
+ if (nc == NULL)
+ (void) fprintf(stderr,
+ "ypwhich: NO netconfig information\n");
+ else {
+ (void) fprintf(stderr,
+ "ypwhich: id %s device %s flag %x protofmly %s proto %s\n",
+ nc->nc_netid, nc->nc_device,
+ (int) nc->nc_flag, nc->nc_protofmly,
+ nc->nc_proto);
+ }
+ if (ua == NULL)
+ (void) fprintf(stderr,
+ "ypwhich: NO netbuf information available from binder\n");
+ else {
+ (void) fprintf(stderr,
+ "maxlen=%d len=%d\naddr=", ua->maxlen, ua->len);
+ for (i = 0; i < ua->len; i++) {
+ if (i != (ua->len - 1))
+ (void) fprintf(stderr,
+ "%d.", ua->buf[i]);
+ else
+ (void) fprintf(stderr,
+ "%d\n", ua->buf[i]);
+ }
+ }
+ }
+ }
+
+}
+#endif
+
+/*
+ * This translates a server address to a name and prints it. If the address
+ * is the same as the local address as returned by get_myaddress, the name
+ * is that retrieved from the kernel. If it's any other address (including
+ * another ip address for the local machine), we'll get a name by using the
+ * standard library routine (which calls the yp).
+ */
+
+/*
+ * This asks any yp server for the map's master.
+ */
+static void
+get_map_master()
+{
+ int err;
+ char *master;
+
+ err = __yp_master_rsvdport(domain, map, &master);
+
+ if (err) {
+ (void) fprintf(stderr,
+ "ypwhich: Can't find the master of %s. Reason: %s.\n",
+ map, yperr_string(err));
+ exit(1);
+ } else {
+ (void) printf("%s\n", master);
+ }
+}
+
+/*
+ * This enumerates the entries within map "ypmaps" in the domain at global
+ * "domain", and prints them out key and value per single line. dump_ypmaps
+ * just decides whether we are (probably) able to speak the new YP protocol,
+ * and dispatches to the appropriate function.
+ */
+static void
+dump_ypmaps()
+{
+ int err;
+ struct dom_binding *binding;
+
+ if (err = __yp_dobind(domain, &binding)) {
+ (void) fprintf(stderr,
+ "dump_ypmaps: Can't bind for domain %s. Reason: %s\n",
+ domain, yperr_string(err));
+ return;
+ }
+
+ if (binding->dom_binding->ypbind_hi_vers >= YPVERS) {
+ dumpmaps(binding);
+ }
+}
+
+static void
+dumpmaps(binding)
+struct dom_binding *binding;
+{
+ enum clnt_stat rpc_stat;
+ int err;
+ char *master;
+ struct ypmaplist *pmpl;
+ struct ypresp_maplist maplist;
+
+ maplist.list = (struct ypmaplist *) NULL;
+
+ rpc_stat = clnt_call(binding->dom_client, YPPROC_MAPLIST,
+ (xdrproc_t) xdr_ypdomain_wrap_string, (caddr_t) &domain,
+ (xdrproc_t) xdr_ypresp_maplist, (caddr_t) &maplist,
+ timeout);
+
+ if (rpc_stat != RPC_SUCCESS) {
+ (void) clnt_perror(binding->dom_client,
+ "ypwhich(dumpmaps): can't get maplist");
+ __yp_rel_binding(binding);
+ exit(1);
+ }
+
+ if (maplist.status != YP_TRUE) {
+ (void) fprintf(stderr,
+ "ypwhich: Can't get maplist. Reason: %s.\n",
+ yperr_string(ypprot_err(maplist.status)));
+ exit(1);
+ }
+ __yp_rel_binding(binding);
+
+ for (pmpl = maplist.list; pmpl; pmpl = pmpl->ypml_next) {
+ (void) printf("%s ", pmpl->ypml_name);
+
+ err = __yp_master_rsvdport(domain, pmpl->ypml_name, &master);
+
+ if (err) {
+ (void) printf("????????\n");
+ (void) fprintf(stderr,
+ "ypwhich: Can't find the master of %s. Reason: %s.\n",
+ pmpl->ypml_name, yperr_string(err));
+ } else {
+ (void) printf("%s\n", master);
+ }
+ }
+}
diff --git a/usr/src/cmd/ypcmd/ypxfr.c b/usr/src/cmd/ypcmd/ypxfr.c
new file mode 100644
index 0000000000..27ce80fa02
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfr.c
@@ -0,0 +1,1885 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley
+ * under license from the Regents of the University of
+ * California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This is a user command which gets a NIS data base from some running
+ * server, and gets it to the local site by using the normal NIS client
+ * enumeration functions. The map is copied to a temp name, then the real
+ * map is removed and the temp map is moved to the real name. ypxfr then
+ * sends a "YPPROC_CLEAR" message to the local server to insure that he will
+ * not hold a removed map open, so serving an obsolete version.
+ *
+ * ypxfr [ -h <host> ] [ -d <domainname> ]
+ * [ -s <domainname> ] [-f] [-c] [-C tid prot name] map
+ *
+ * If the host is ommitted, ypxfr will attempt to discover the master by
+ * using normal NIS services. If it can't get the record, it will use
+ * the address of the callback, if specified. If the host is specified
+ * as an internet address, no NIS services need to be locally available.
+ *
+ * If the domain is not specified, the default domain of the local machine
+ * is used.
+ *
+ * If the -f flag is used, the transfer will be done even if the master's
+ * copy is not newer than the local copy.
+ *
+ * The -c flag suppresses the YPPROC_CLEAR request to the local ypserv. It
+ * may be used if ypserv isn't currently running to suppress the error message.
+ *
+ * The -C flag is used to pass callback information to ypxfr when it is
+ * activated by ypserv. The callback information is used to send a
+ * yppushresp_xfr message with transaction id "tid" to a yppush process
+ * speaking a transient protocol number "prot". The yppush program is
+ * running on the host "name".
+ *
+ * The -s option is used to specify a source domain which may be
+ * different from the destination domain, for transfer of maps
+ * that are identical in different domains (e.g. services.byname)
+ *
+ */
+
+#include <ndbm.h>
+#undef NULL
+#define DATUM
+
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <rpc/rpc.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <rpcsvc/nis.h>
+#include "ypdefs.h"
+#include "yp_b.h"
+#include "shim.h"
+#include "yptol.h"
+
+USE_YP_MASTER_NAME
+USE_YP_SECURE
+USE_YP_INTERDOMAIN
+USE_YP_LAST_MODIFIED
+USE_YPDBPATH
+USE_DBM
+
+#define PARANOID 1 /* make sure maps have the right # entries */
+
+#define CALLINTER_TRY 10 /* Seconds between callback tries */
+#define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */
+
+DBM *db;
+
+/* ypxfr never uses N2L mode */
+bool_t yptol_mode = FALSE;
+
+int debug = FALSE;
+int treepush = FALSE;
+#define TREEPUSH 1
+int defwrite = TRUE;
+
+char *domain = NULL;
+char *source = NULL;
+char *map = NULL;
+char *master = NULL;
+char *pushhost = NULL;
+/*
+ * The name of the xfer peer as specified as a
+ * -h option, -C name option or from querying the NIS
+ */
+struct dom_binding master_server; /* To talk to above */
+unsigned int master_prog_vers; /* YPVERS (barfs at YPOLDVERS !) */
+char *master_name = NULL; /* Map's master as contained in the map */
+unsigned *master_version = NULL; /* Order number as contained in the map */
+char *master_ascii_version; /* ASCII order number as contained in the map */
+bool fake_master_version = FALSE;
+/*
+ * TRUE only if there's no order number in
+ * the map, and the user specified -f
+ */
+bool force = FALSE; /* TRUE iff user specified -f flag */
+bool logging = FALSE; /* TRUE iff no tty, but log file exists */
+bool check_count = FALSE; /* TRUE causes counts to be checked */
+bool send_clear = TRUE; /* FALSE iff user specified -c flag */
+bool callback = FALSE;
+/*
+ * TRUE iff -C flag set. tid, proto and name
+ * will be set to point to the command line args.
+ */
+bool secure_map = FALSE; /* TRUE if there is yp_secure in the map */
+bool interdomain_map = FALSE;
+/*
+ * TRUE if there is yp_interdomain in either
+ * the local or the master version of the map
+ */
+int interdomain_sz = 0; /* Size of the interdomain value */
+#define UDPINTER_TRY 10 /* Seconds between tries for udp */
+#define UDPTIMEOUT UDPINTER_TRY*4 /* Total timeout for udp */
+#define CALLINTER_TRY 10 /* Seconds between callback tries */
+#define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */
+struct timeval udp_timeout = { UDPTIMEOUT, 0};
+struct timeval tcp_timeout = { 180, 0}; /* Timeout for map enumeration */
+
+char *interdomain_value; /* place to store the interdomain value */
+char *tid;
+char *proto;
+int entry_count; /* counts entries in the map */
+char logfile[] = "/var/yp/ypxfr.log";
+static char err_usage[] =
+"Usage:\n\
+ypxfr [-f] [ -h host ] [ -d domainname ]\n\
+ [ -s domainname ] [-c] [-C tid prot servname ] map\n\n\
+where\n\
+ -f forces transfer even if the master's copy is not newer.\n\
+ host is the server from where the map should be transfered\n\
+ -d domainname is specified if other than the default domain\n\
+ -s domainname is a source for the map that is same across domains\n\
+ -c inhibits sending a \"Clear map\" message to the local ypserv.\n\
+ -C is for use only by ypserv to pass callback information.\n";
+char err_bad_args[] =
+ "%s argument is bad.\n";
+char err_cant_get_kname[] =
+ "Can't get %s back from system call.\n";
+char err_null_kname[] =
+ "%s hasn't been set on this machine.\n";
+char err_bad_hostname[] = "hostname";
+char err_bad_mapname[] = "mapname";
+char err_bad_domainname[] = "domainname";
+char err_udp_failure[] =
+ "Can't set up a udp connection to ypserv on host %s.\n";
+char yptempname_prefix[] = "ypxfr_map.";
+char ypbkupname_prefix[] = "ypxfr_bkup.";
+
+void get_command_line_args();
+bool bind_to_server();
+bool ping_server();
+bool get_private_recs();
+bool get_order();
+bool get_v1order();
+bool get_v2order();
+bool get_misc_recs();
+bool get_master_name();
+bool get_v1master_name();
+bool get_v2master_name();
+void find_map_master();
+bool move_map();
+unsigned get_local_version();
+void mkfilename();
+void mk_tmpname();
+bool get_map();
+bool add_private_entries();
+bool new_mapfiles();
+void del_mapfiles();
+void set_output();
+void logprintf();
+bool send_ypclear();
+void xfr_exit();
+void send_callback();
+int ypall_callback();
+int map_yperr_to_pusherr();
+extern CLIENT *__yp_clnt_create_rsvdport();
+
+bool_t is_yptol_mode();
+
+extern int errno;
+
+
+/*
+ * This is the mainline for the ypxfr process.
+ */
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+
+{
+
+ static char default_domain_name[YPMAXDOMAIN];
+ static unsigned big = 0xffffffff;
+ int status;
+
+ set_output();
+
+ /*
+ * Inter-process lock synchronization structure. Since slave servers
+ * get their maps from another NIS server rather than LDAP they can
+ * never run in N2L mode. We thus do not have to init the update
+ * locking mechanism.
+ */
+ if (init_lock_map() == FALSE) {
+ exit(1);
+ }
+
+ get_command_line_args(argc, argv);
+
+ if (!domain) {
+
+ if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
+ domain = default_domain_name;
+ } else {
+ logprintf(err_cant_get_kname,
+ err_bad_domainname);
+ xfr_exit(YPPUSH_RSRC);
+ }
+
+ if (strlen(domain) == 0) {
+ logprintf(err_null_kname,
+ err_bad_domainname);
+ xfr_exit(YPPUSH_RSRC);
+ }
+ }
+ if (!source)
+ source = domain;
+
+ if (!master) {
+ find_map_master();
+ }
+ /*
+ * if we were unable to get the master name, either from
+ * the -h option or from -C "name" option or from NIS,
+ * we are doomed !
+ */
+ if (!master) {
+ xfr_exit(YPPUSH_MADDR);
+ }
+
+ if (!bind_to_server(master, &master_server,
+ &master_prog_vers, &status)) {
+ xfr_exit(status);
+ }
+
+ if (!get_private_recs(&status)) {
+ xfr_exit(status);
+ }
+
+ if (!master_version) {
+
+ if (force) {
+ master_version = &big;
+ fake_master_version = TRUE;
+ } else {
+ logprintf(
+"Can't get order number for map %s from server at %s: use the -f flag.\n",
+ map, master);
+ xfr_exit(YPPUSH_FORCE);
+ }
+ }
+
+ if (!move_map(&status)) {
+ xfr_exit(status);
+ }
+
+ if (send_clear && !send_ypclear(&status)) {
+ xfr_exit(status);
+ }
+
+ if (logging) {
+ logprintf("Transferred map %s from %s (%d entries).\n",
+ map, master, entry_count);
+ }
+
+ xfr_exit(YPPUSH_SUCC);
+ /* NOTREACHED */
+}
+
+/*
+ * This decides whether we're being run interactively or not, and, if not,
+ * whether we're supposed to be logging or not. If we are logging, it sets
+ * up stderr to point to the log file, and sets the "logging"
+ * variable. If there's no logging, the output goes in the bit bucket.
+ * Logging output differs from interactive output in the presence of a
+ * timestamp, present only in the log file. stderr is reset, too, because it
+ * it's used by various library functions, including clnt_perror.
+ */
+void
+set_output()
+{
+ if (!isatty(1)) {
+ if (access(logfile, W_OK)) {
+ (void) freopen("/dev/null", "w", stderr);
+ } else {
+ (void) freopen(logfile, "a", stderr);
+ logging = TRUE;
+ }
+ }
+}
+/*
+ * This constructs a logging record.
+ */
+void
+logprintf(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+/*VARARGS*/
+{
+ struct timeval t;
+
+ fseek(stderr, 0, 2);
+ if (logging) {
+ (void) gettimeofday(&t, NULL);
+ (void) fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec));
+ }
+ (void) fprintf(stderr, (char *)arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7);
+ fflush(stderr);
+}
+
+/*
+ * This does the command line argument processing.
+ */
+void
+get_command_line_args(argc, argv)
+ int argc;
+ char **argv;
+
+{
+ argv++;
+
+ if (argc < 2) {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ while (--argc) {
+
+ if ((*argv)[0] == '-') {
+
+ switch ((*argv)[1]) {
+
+ case 'f': {
+ force = TRUE;
+ argv++;
+ break;
+ }
+
+ case 'D': {
+ debug = TRUE;
+ argv++;
+ break;
+ }
+
+ case 'T': {
+ treepush = TRUE;
+ argv++;
+ break;
+ }
+ case 'P': {
+ check_count = TRUE;
+ argv++;
+ break;
+ }
+ case 'W': {
+ defwrite = FALSE;
+ argv++;
+ break;
+ }
+ case 'c': {
+ send_clear = FALSE;
+ argv++;
+ break;
+ }
+
+ case 'h': {
+
+ if (argc > 1) {
+ argv++;
+ argc--;
+ master = *argv;
+ argv++;
+
+ if (strlen(master) > 256) {
+ logprintf(
+ err_bad_args,
+ err_bad_hostname);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ } else {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ break;
+ }
+
+ case 'd':
+ if (argc > 1) {
+ argv++;
+ argc--;
+ domain = *argv;
+ argv++;
+
+ if (strlen(domain) > YPMAXDOMAIN) {
+ logprintf(
+ err_bad_args,
+ err_bad_domainname);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ } else {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+ break;
+
+ case 's':
+ if (argc > 1) {
+ argv++;
+ argc--;
+ source = *argv;
+ argv++;
+
+ if (strlen(source) > YPMAXDOMAIN) {
+ logprintf(
+ err_bad_args,
+ err_bad_domainname);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ } else {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+ break;
+
+ case 'C':
+ if (argc > 3) {
+ callback = TRUE;
+ tid = *(++argv);
+ proto = *(++argv);
+ pushhost = *(++argv);
+ if (strlen(pushhost) > 256) {
+ logprintf(err_bad_args, err_bad_hostname);
+
+ xfr_exit(YPPUSH_BADARGS);
+ }
+ argc -= 3;
+ argv++;
+ } else {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+ break;
+
+ case 'b': {
+ interdomain_map = TRUE;
+ interdomain_value = "";
+ interdomain_sz = 0;
+ argv++;
+ break;
+ }
+
+
+ default: {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ }
+
+ } else {
+
+ if (!map) {
+ map = *argv;
+ argv++;
+
+ if (strlen(map) > YPMAXMAP) {
+ logprintf(err_bad_args,
+ err_bad_mapname);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+
+ } else {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+ }
+ }
+
+ if (!map) {
+ logprintf(err_usage);
+ xfr_exit(YPPUSH_BADARGS);
+ }
+}
+
+/*
+ * This tries to get the master name for the named map, from any
+ * server's version, using the vanilla NIS client interface. If we get a
+ * name back, the global "master" gets pointed to it.
+ */
+void
+find_map_master()
+{
+ int err;
+
+ if (err = __yp_master_rsvdport(source, map, &master)) {
+ logprintf("Can't get master of %s. Reason: %s.\n", map,
+ yperr_string(err));
+ }
+
+ yp_unbind(source);
+}
+
+#ifdef TREEPUSH
+chk_treepush(name)
+char *name;
+{
+ char inmap[256];
+ char inkey[256];
+ int inkeylen;
+ char *outval;
+ int outvallen;
+ int err;
+ outval = NULL;
+ inkey[0] = 0;
+ strcpy(inmap, "ypslaves.");
+ strcat(inmap, name);
+ gethostname(inkey, 256);
+ inkeylen = strlen(inkey);
+
+ err = yp_match(source, inmap, inkey, inkeylen, &outval, &outvallen);
+ yp_unbind(source);
+ return (err);
+}
+#endif
+
+/*
+ * This sets up a udp connection to speak the correct program and version
+ * to a NIS server. vers is set to YPVERS, doesn't give a damn about
+ * YPOLDVERS.
+ */
+bool
+bind_to_server(host, pdomb, vers, status)
+ char *host;
+ struct dom_binding *pdomb;
+ unsigned int *vers;
+ int *status;
+{
+ if (ping_server(host, pdomb, YPVERS, status)) {
+ *vers = YPVERS;
+ return (TRUE);
+ } else
+ return (FALSE);
+}
+
+/*
+ * This sets up a UDP channel to a server which is assumed to speak an input
+ * version of YPPROG. The channel is tested by pinging the server. In all
+ * error cases except "Program Version Number Mismatch", the error is
+ * reported, and in all error cases, the client handle is destroyed and the
+ * socket associated with the channel is closed.
+ */
+bool
+ping_server(host, pdomb, vers, status)
+ char *host;
+ struct dom_binding *pdomb;
+ unsigned int vers;
+ int *status;
+{
+ enum clnt_stat rpc_stat;
+
+ if ((pdomb->dom_client = __yp_clnt_create_rsvdport(host, YPPROG, vers,
+ 0, 0, 0)) != 0) {
+
+ /*
+ * if we are on a c2 system, we should only accept data
+ * from a server which is on a reserved port.
+ */
+ /*
+ * NUKE this for 5.0DR.
+ *
+ * if (issecure() &&
+ * (pdomb->dom_server_addr.sin_family != AF_INET ||
+ * pdomb->dom_server_addr.sin_port >= IPPORT_RESERVED)) {
+ * clnt_destroy(pdomb->dom_client);
+ * close(pdomb->dom_socket);
+ * (void) logprintf("bind_to_server: \
+ * server is not using a privileged port\n");
+ * *status = YPPUSH_YPERR;
+ * return (FALSE);
+ * }
+ */
+
+ rpc_stat = clnt_call(pdomb->dom_client, YPBINDPROC_NULL,
+ xdr_void, 0, xdr_void, 0, udp_timeout);
+
+ if (rpc_stat == RPC_SUCCESS) {
+ return (TRUE);
+ } else {
+ clnt_destroy(pdomb->dom_client);
+ if (rpc_stat != RPC_PROGVERSMISMATCH) {
+ (void) clnt_perror(pdomb->dom_client,
+ "ypxfr: bind_to_server clnt_call error");
+ }
+
+ *status = YPPUSH_RPC;
+ return (FALSE);
+ }
+ } else {
+ logprintf("bind_to_server __clnt_create_rsvd error");
+ (void) clnt_pcreateerror("");
+ fflush(stderr);
+ *status = YPPUSH_RPC;
+ return (FALSE);
+ }
+}
+
+/*
+ * This gets values for the YP_LAST_MODIFIED and YP_MASTER_NAME keys from the
+ * master server's version of the map. Values are held in static variables
+ * here. In the success cases, global pointer variables are set to point at
+ * the local statics.
+ */
+bool
+get_private_recs(pushstat)
+ int *pushstat;
+{
+ static char anumber[20];
+ static unsigned number;
+ static char name[YPMAXPEER + 1];
+ int status;
+
+ status = 0;
+
+ if (get_order(anumber, &number, &status)) {
+ master_version = &number;
+ master_ascii_version = anumber;
+ if (debug) fprintf(stderr,
+ "ypxfr: Master Version is %s\n", master_ascii_version);
+ } else {
+
+ if (status != 0) {
+ *pushstat = status;
+ if (debug) fprintf(stderr,
+ "ypxfr: Couldn't get map's master version number, \
+ status was %d\n", status);
+ return (FALSE);
+ }
+ }
+
+ if (get_master_name(name, &status)) {
+ master_name = name;
+ if (debug) fprintf(stderr,
+ "ypxfr: Maps master is '%s'\n", master_name);
+ } else {
+
+ if (status != 0) {
+ *pushstat = status;
+ if (debug) fprintf(stderr,
+ "ypxfr: Couldn't get map's master name, status was %d\n",
+ status);
+ return (FALSE);
+ }
+ master_name = master;
+ }
+
+ if (debug)
+ fprintf(stderr,
+ "ypxfr: Getting private records from master.\n");
+ if (get_misc_recs(&status)) {
+ if (debug)
+ fprintf(stderr,
+ "ypxfr: Masters map %s secure and %s an interdomain map.\n",
+ (secure_map) ? "is" : "is not",
+ (interdomain_map) ? "is" : "is not");
+ } else {
+ if (status != 0) {
+ *pushstat = status;
+ if (debug)
+ fprintf(stderr,
+ "ypxfr: Couldn't get state of secure and interdomain flags in map.\n");
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
+
+/*
+ * This gets the map's order number from the master server
+ */
+bool
+get_order(an, n, pushstat)
+ char *an;
+ unsigned *n;
+ int *pushstat;
+{
+ if (master_prog_vers == YPVERS) {
+ return (get_v2order(an, n, pushstat));
+ } else
+ return (FALSE);
+}
+
+bool
+get_v2order(an, n, pushstat)
+ char *an;
+ unsigned *n;
+ int *pushstat;
+{
+ struct ypreq_nokey req;
+ struct ypresp_order resp;
+ int retval;
+
+ req.domain = source;
+ req.map = map;
+
+ /*
+ * Get the map''s order number, null-terminate it and store it,
+ * and convert it to binary and store it again.
+ */
+ retval = FALSE;
+
+ if ((enum clnt_stat) clnt_call(master_server.dom_client,
+ YPPROC_ORDER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
+ (xdrproc_t)xdr_ypresp_order, (char *)&resp,
+ udp_timeout) == RPC_SUCCESS) {
+
+ if (resp.status == YP_TRUE) {
+ sprintf(an, "%d", resp.ordernum);
+ *n = resp.ordernum;
+ retval = TRUE;
+ } else if (resp.status != YP_BADDB) {
+ *pushstat = ypprot_err(resp.status);
+
+ if (!logging) {
+ logprintf(
+ "(info) Can't get order number from ypserv at %s. Reason: %s.\n",
+ master, yperr_string(
+ ypprot_err(resp.status)));
+ }
+ }
+
+ CLNT_FREERES(master_server.dom_client,
+ (xdrproc_t)xdr_ypresp_order,
+ (char *)&resp);
+ } else {
+ *pushstat = YPPUSH_RPC;
+ logprintf("ypxfr(get_v2order) RPC call to %s failed", master);
+ clnt_perror(master_server.dom_client, "");
+ }
+
+ return (retval);
+}
+
+/*
+ * Pick up the state of the YP_SECURE and YP_INTERDOMAIN records from the
+ * master. Only works on 4.0 V2 masters that will match a YP_ private key
+ * when asked to explicitly.
+ */
+bool
+get_misc_recs(pushstat)
+ int *pushstat;
+{
+ struct ypreq_key req;
+ struct ypresp_val resp;
+ int retval;
+
+ req.domain = source;
+ req.map = map;
+ req.keydat.dptr = yp_secure;
+ req.keydat.dsize = yp_secure_sz;
+
+ resp.valdat.dptr = NULL;
+ resp.valdat.dsize = 0;
+
+ /*
+ * Get the value of the IS_SECURE key in the map.
+ */
+ retval = FALSE;
+
+ if (debug)
+ fprintf(stderr, "ypxfr: Checking masters secure key.\n");
+ if ((enum clnt_stat) clnt_call(master_server.dom_client,
+ YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req,
+ (xdrproc_t)xdr_ypresp_val, (char *)&resp,
+ udp_timeout) == RPC_SUCCESS) {
+ if (resp.status == YP_TRUE) {
+ if (debug)
+ fprintf(stderr, "ypxfr: SECURE\n");
+ secure_map = TRUE;
+ retval = TRUE;
+ } else if ((resp.status != YP_NOKEY) &&
+ (resp.status != YP_VERS) &&
+ (resp.status != YP_NOMORE)) {
+ *pushstat = ypprot_err(resp.status);
+
+ if (!logging) {
+ logprintf(
+ "(info) Can't get secure flag from ypserv at %s. Reason: %s.\n",
+ master, yperr_string(
+ ypprot_err(resp.status)));
+ }
+ }
+
+ CLNT_FREERES(master_server.dom_client,
+ (xdrproc_t)xdr_ypresp_val,
+ (char *)&resp);
+ } else {
+ *pushstat = YPPUSH_RPC;
+ logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master);
+ clnt_perror(master_server.dom_client, "");
+ }
+
+ if (debug)
+ fprintf(stderr, "ypxfr: Checking masters INTERDOMAIN key.\n");
+ req.keydat.dptr = yp_interdomain;
+ req.keydat.dsize = yp_interdomain_sz;
+
+ resp.valdat.dptr = NULL;
+ resp.valdat.dsize = 0;
+
+ /*
+ * Get the value of the INTERDOMAIN key in the map.
+ */
+
+ if ((enum clnt_stat) clnt_call(master_server.dom_client,
+ YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req,
+ (xdrproc_t)xdr_ypresp_val, (char *)&resp,
+ udp_timeout) == RPC_SUCCESS) {
+ if (resp.status == YP_TRUE) {
+ if (debug)
+ fprintf(stderr, "ypxfr: INTERDOMAIN\n");
+ interdomain_map = TRUE;
+ interdomain_value = (char *)malloc(resp.valdat.dsize+1);
+ (void) memmove(interdomain_value, resp.valdat.dptr,
+ resp.valdat.dsize);
+ *(interdomain_value+resp.valdat.dsize) = '\0';
+ interdomain_sz = resp.valdat.dsize;
+ retval = TRUE;
+ } else if ((resp.status != YP_NOKEY) &&
+ (resp.status != YP_VERS) &&
+ (resp.status != YP_NOMORE)) {
+ *pushstat = ypprot_err(resp.status);
+
+ if (!logging) {
+ logprintf(
+ "(info) Can't get interdomain flag from ypserv at %s. Reason: %s.\n",
+ master, yperr_string(
+ ypprot_err(resp.status)));
+ }
+ }
+
+ CLNT_FREERES(master_server.dom_client,
+ (xdrproc_t)xdr_ypresp_val,
+ (char *)&resp);
+ } else {
+ *pushstat = YPPUSH_RPC;
+ logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master);
+ clnt_perror(master_server.dom_client, "");
+ }
+
+
+ return (retval);
+}
+
+/*
+ * This gets the map's master name from the master server
+ */
+bool
+get_master_name(name, pushstat)
+ char *name;
+ int *pushstat;
+{
+ if (master_prog_vers == YPVERS) {
+ return (get_v2master_name(name, pushstat));
+ } else
+ return (FALSE);
+}
+
+bool
+get_v2master_name(name, pushstat)
+ char *name;
+ int *pushstat;
+{
+ struct ypreq_nokey req;
+ struct ypresp_master resp;
+ int retval;
+
+ req.domain = source;
+ req.map = map;
+ resp.master = NULL;
+ retval = FALSE;
+
+ if ((enum clnt_stat) clnt_call(master_server.dom_client,
+ YPPROC_MASTER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
+ (xdrproc_t)xdr_ypresp_master, (char *)&resp,
+ udp_timeout) == RPC_SUCCESS) {
+
+ if (resp.status == YP_TRUE) {
+ strcpy(name, resp.master);
+ retval = TRUE;
+ } else if (resp.status != YP_BADDB) {
+ *pushstat = ypprot_err(resp.status);
+
+ if (!logging) {
+ logprintf(
+"(info) Can't get master name from ypserv at %s. Reason: %s.\n",
+ master, yperr_string(
+ ypprot_err(resp.status)));
+ }
+ }
+
+ CLNT_FREERES(master_server.dom_client,
+ (xdrproc_t)xdr_ypresp_master,
+ (char *)&resp);
+ } else {
+ *pushstat = YPPUSH_RPC;
+ logprintf(
+ "ypxfr(get_v2master_name) RPC call to %s failed", master);
+ clnt_perror(master_server.dom_client, "");
+ }
+
+ return (retval);
+}
+
+/*
+ * This does the work of transferring the map.
+ */
+bool
+move_map(pushstat)
+ int *pushstat;
+{
+ unsigned local_version;
+ char map_name[MAXNAMLEN + 1];
+ char tmp_name[MAXNAMLEN + 1];
+ char bkup_name[MAXNAMLEN + 1];
+ char an[11];
+ unsigned n;
+ datum key;
+ datum val;
+ int hgstatus;
+
+ mkfilename(map_name);
+
+ if (!force) {
+ local_version = get_local_version(map_name);
+ if (debug) fprintf(stderr,
+ "ypxfr: Local version of map '%s' is %d\n",
+ map_name, local_version);
+
+ if (local_version >= *master_version) {
+ logprintf(
+ "Map %s at %s is not more recent than local.\n",
+ map, master);
+ *pushstat = YPPUSH_AGE;
+ return (FALSE);
+ }
+ }
+
+ mk_tmpname(yptempname_prefix, tmp_name);
+
+ if (!new_mapfiles(tmp_name)) {
+ logprintf(
+ "Can't create temp map %s.\n", tmp_name);
+ *pushstat = YPPUSH_FILE;
+ return (FALSE);
+ }
+
+ if ((hgstatus = ypxfrd_getdbm(tmp_name, master, source, map)) < 0)
+ {
+ logprintf(
+"(info) %s %s %s ypxfrd getdbm failed (reason = %d) -- using ypxfr\n",
+ master, domain, map, hgstatus);
+
+ db = dbm_open(tmp_name, O_RDWR + O_CREAT + O_TRUNC, 0644);
+ if (db == NULL) {
+ logprintf(
+ "Can't dbm init temp map %s.\n", tmp_name);
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+ if (defwrite) dbm_setdefwrite(db);
+
+ if (!get_map(tmp_name, pushstat)) {
+ del_mapfiles(tmp_name);
+ return (FALSE);
+ }
+
+ if (!add_private_entries(tmp_name)) {
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+
+ /*
+ * Decide whether the map just transferred is a secure map.
+ * If we already know the local version was secure, we do not
+ * need to check this version.
+ */
+ if (!secure_map) {
+ key.dptr = yp_secure;
+ key.dsize = yp_secure_sz;
+ val = dbm_fetch(db, key);
+ if (val.dptr != NULL) {
+ secure_map = TRUE;
+ }
+ }
+
+ if (dbm_close_status(db) < 0) {
+ logprintf(
+ "Can't do dbm close operation on temp map %s.\n",
+ tmp_name);
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+
+ if (!get_order(an, &n, pushstat)) {
+ return (FALSE);
+ }
+ if (n != *master_version) {
+ logprintf(
+ "Version skew at %s while transferring map %s.\n",
+ master, map);
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_SKEW;
+ return (FALSE);
+ }
+
+ if (check_count)
+ if (!count_mismatch(tmp_name, entry_count)) {
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+ } else {
+ /* touch up the map */
+ db = dbm_open(tmp_name, 2, 0644);
+ if (db == NULL) {
+ logprintf(
+ "Can't dbm init temp map %s.\n", tmp_name);
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+
+
+ if (!add_private_entries(tmp_name)) {
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+
+ /*
+ * Decide whether the map just transferred is a secure map.
+ * If we already know the local version was secure, we do not
+ * need to check this version.
+ */
+ if (!secure_map) {
+ key.dptr = yp_secure;
+ key.dsize = yp_secure_sz;
+ val = dbm_fetch(db, key);
+ if (val.dptr != NULL) {
+ secure_map = TRUE;
+ }
+ }
+
+ if (dbm_close_status(db) < 0) {
+ logprintf(
+ "Can't do dbm close operation on temp map %s.\n",
+ tmp_name);
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_DBM;
+ return (FALSE);
+ }
+
+ }
+
+ if (lock_map(map_name) == 0) {
+ del_mapfiles(tmp_name);
+ logprintf("Lock error on %s\n", map_name);
+ *pushstat = YPPUSH_FILE;
+ return (FALSE);
+ }
+ if (!check_map_existence(map_name)) {
+
+ if (!rename_map(tmp_name, map_name, secure_map)) {
+ del_mapfiles(tmp_name);
+ logprintf(
+ "Rename error: couldn't mv %s to %s.\n",
+ tmp_name, map_name);
+ *pushstat = YPPUSH_FILE;
+ unlock_map(map_name);
+ return (FALSE);
+ }
+
+ } else {
+ mk_tmpname(ypbkupname_prefix, bkup_name);
+
+ if (!rename_map(map_name, bkup_name, secure_map)) {
+ (void) rename_map(bkup_name, map_name, secure_map);
+ logprintf(
+ "Rename error: check that old %s is still intact.\n",
+ map_name);
+ del_mapfiles(tmp_name);
+ *pushstat = YPPUSH_FILE;
+ unlock_map(map_name);
+ return (FALSE);
+ }
+
+ if (rename_map(tmp_name, map_name, secure_map)) {
+ del_mapfiles(bkup_name);
+ } else {
+ del_mapfiles(tmp_name);
+ (void) rename_map(bkup_name, map_name, secure_map);
+ logprintf(
+ "Rename error: check that old %s is still intact.\n",
+ map_name);
+ *pushstat = YPPUSH_FILE;
+ unlock_map(map_name);
+ return (FALSE);
+ }
+ }
+ if (unlock_map(map_name) == 0)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * This tries to get the order number out of the local version of the map.
+ * If the attempt fails for any version, the function will return "0"
+ */
+unsigned
+get_local_version(name)
+ char *name;
+{
+ datum key;
+ datum val;
+ char number[11];
+ DBM *db;
+
+ if (!check_map_existence(name)) {
+ return (0);
+ }
+ if (debug) fprintf(stderr,
+ "ypxfr: Map does exist, checking version now.\n");
+
+ if ((db = dbm_open(name, 0, 0)) == 0) {
+ return (0);
+ }
+
+ key.dptr = yp_last_modified;
+ key.dsize = yp_last_modified_sz;
+ val = dbm_fetch(db, key);
+ if (!val.dptr) { /* Check to see if dptr is NULL */
+ return (0);
+ }
+ if (val.dsize == 0 || val.dsize > 10) {
+ return (0);
+ }
+ /* Now save this value while we have it available */
+ (void) memmove(number, val.dptr, val.dsize);
+ number[val.dsize] = '\0';
+
+ /*
+ * Now check to see if it is 'secure'. If we haven't already
+ * determined that it is secure in get_private_recs() then we check
+ * the local map here.
+ */
+ if (!secure_map) {
+ key.dptr = yp_secure;
+ key.dsize = yp_secure_sz;
+ val = dbm_fetch(db, key);
+ secure_map = (val.dptr != NULL);
+ }
+
+ /*
+ * Now check to see if interdomain requests are made of the local
+ * map. Keep the value around if they are.
+ */
+ if (!interdomain_map) {
+ key.dptr = yp_interdomain;
+ key.dsize = yp_interdomain_sz;
+ val = dbm_fetch(db, key);
+ if (interdomain_map = (val.dptr != NULL)) {
+ interdomain_value = (char *)malloc(val.dsize+1);
+ (void) memmove(interdomain_value, val.dptr, val.dsize);
+ *(interdomain_value+val.dsize) = '\0';
+ interdomain_sz = val.dsize;
+ }
+ }
+
+ /* finish up */
+ (void) dbm_close_status(db);
+
+ return ((unsigned)atoi(number));
+}
+
+/*
+ * This constructs a file name for a map, minus its dbm_dir
+ * or dbm_pag extensions
+ */
+void
+mkfilename(ppath)
+ char *ppath;
+{
+ bool_t yptol_mode;
+ int len;
+
+ /* Work out if we are in yptol mode */
+ yptol_mode = is_yptol_mode();
+
+ len = strlen(domain) + strlen(map) + strlen(ypdbpath) + 3;
+ if (yptol_mode)
+ len += strlen(NTOL_PREFIX);
+
+ if (len > (MAXNAMLEN + 1)) {
+ logprintf("Map name string too long.\n");
+ }
+
+ (void) strcpy(ppath, ypdbpath);
+ (void) strcat(ppath, "/");
+ (void) strcat(ppath, domain);
+ (void) strcat(ppath, "/");
+ if (yptol_mode)
+ (void) strcat(ppath, NTOL_PREFIX);
+ (void) strcat(ppath, map);
+}
+
+/*
+ * This returns a temporary name for a map transfer minus its dbm_dir or
+ * dbm_pag extensions.
+ */
+void
+mk_tmpname(prefix, xfr_name)
+ char *prefix;
+ char *xfr_name;
+{
+ char xfr_anumber[10];
+ long xfr_number;
+
+ if (!xfr_name) {
+ return;
+ }
+
+ xfr_number = getpid();
+ (void) sprintf(xfr_anumber, "%d", xfr_number);
+
+ (void) strcpy(xfr_name, ypdbpath);
+ (void) strcat(xfr_name, "/");
+ (void) strcat(xfr_name, domain);
+ (void) strcat(xfr_name, "/");
+ (void) strcat(xfr_name, prefix);
+ (void) strcat(xfr_name, map);
+ (void) strcat(xfr_name, ".");
+ (void) strcat(xfr_name, xfr_anumber);
+}
+
+/*
+ * This deletes the .pag and .dir files which implement a map.
+ *
+ * Note: No error checking is done here for a garbage input file name or for
+ * failed unlink operations.
+ */
+void
+del_mapfiles(basename)
+ char *basename;
+{
+ char dbfilename[MAXNAMLEN + 1];
+
+ if (!basename) {
+ return;
+ }
+
+ strcpy(dbfilename, basename);
+ strcat(dbfilename, dbm_pag);
+ unlink(dbfilename);
+ strcpy(dbfilename, basename);
+ strcat(dbfilename, dbm_dir);
+ unlink(dbfilename);
+}
+
+/*
+ * This creates <pname>.dir and <pname>.pag
+ */
+bool
+new_mapfiles(pname)
+ char *pname;
+{
+ char dbfile[MAXNAMLEN + 1];
+ int f;
+ int len;
+
+ if (!pname || ((len = strlen(pname)) == 0) ||
+ (len + 5) > (MAXNAMLEN + 1)) {
+ return (FALSE);
+ }
+
+ errno = 0;
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, dbm_dir);
+
+ if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC), 0600)) >= 0) {
+ (void) close(f);
+ (void) strcpy(dbfile, pname);
+ (void) strcat(dbfile, dbm_pag);
+
+ if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC),
+ 0600)) >= 0) {
+ (void) close(f);
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+
+ } else {
+ return (FALSE);
+ }
+}
+
+count_callback(status)
+ int status;
+{
+ if (status != YP_TRUE) {
+
+ if (status != YP_NOMORE) {
+ logprintf(
+ "Error from ypserv on %s (ypall_callback) = %s.\n",
+ master, yperr_string(ypprot_err(status)));
+ }
+
+ return (TRUE);
+ }
+
+ entry_count++;
+ return (FALSE);
+}
+
+/*
+ * This counts the entries in the dbm file after the transfer to
+ * make sure that the dbm file was built correctly.
+ * Returns TRUE if everything is OK, FALSE if they mismatch.
+ */
+count_mismatch(pname, oldcount)
+ char *pname;
+ int oldcount;
+{
+ datum key;
+ DBM *db;
+#ifdef REALLY_PARANOID
+ struct ypall_callback cbinfo;
+ struct ypreq_nokey allreq;
+ enum clnt_stat s;
+ struct dom_binding domb;
+ datum value;
+#endif /* REALLY_PARANOID */
+
+ entry_count = 0;
+ db = dbm_open(pname, 0, 0);
+ if (db) {
+ for (key = dbm_firstkey(db);
+ key.dptr != NULL; key = dbm_nextkey(db))
+ entry_count++;
+ dbm_close_status(db);
+ }
+
+ if (oldcount != entry_count) {
+ logprintf(
+ "*** Count mismatch in dbm file %s: old=%d, new=%d ***\n",
+ map, oldcount, entry_count);
+ return (FALSE);
+ }
+
+#ifdef REALLY_PARANOID
+
+ if ((domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG,
+ master_prog_vers,
+ "tcp6", 0, 0)) == 0 &&
+ (domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG,
+ master_prog_vers,
+ "tcp", 0, 0)) == 0) {
+ clnt_pcreateerror("ypxfr (mismatch) - TCP channel "
+ "create failure");
+ return (FALSE);
+ }
+
+ if (master_prog_vers == YPVERS) {
+ int tmpstat;
+
+ allreq.domain = source;
+ allreq.map = map;
+ cbinfo.foreach = count_callback;
+ tmpstat = 0;
+ cbinfo.data = (char *)&tmpstat;
+
+ entry_count = 0;
+ s = clnt_call(domb.dom_client, YPPROC_ALL, xdr_ypreq_nokey,
+ &allreq, xdr_ypall, &cbinfo, tcp_timeout);
+
+ if (tmpstat == 0) {
+ if (s == RPC_SUCCESS) {
+ } else {
+ clnt_perror(domb.dom_client,
+ "ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
+ return (FALSE);
+ }
+
+ } else {
+ return (FALSE);
+ }
+
+ } else {
+ logprintf("Wrong version number!\n");
+ return (FALSE);
+ }
+ clnt_destroy(domb.dom_client);
+ close(domb.dom_socket);
+ entry_count += 2; /* add in YP_entries */
+ if (oldcount != entry_count) {
+ logprintf(
+ "*** Count mismatch after enumerate %s: old=%d, new=%d ***\n",
+ map, oldcount, entry_count);
+ return (FALSE);
+ }
+#endif /* REALLY_PARANOID */
+
+ return (TRUE);
+}
+
+/*
+ * This sets up a TCP connection to the master server, and either gets
+ * ypall_callback to do all the work of writing it to the local dbm file
+ * (if the ypserv is current version), or does it itself for an old ypserv.
+ */
+bool
+get_map(pname, pushstat)
+ char *pname;
+ int *pushstat;
+{
+ struct dom_binding domb;
+ enum clnt_stat s;
+ struct ypreq_nokey allreq;
+ struct ypall_callback cbinfo;
+ bool retval = FALSE;
+ int tmpstat;
+ int recvsiz = 24 * 1024;
+ struct netconfig *nconf;
+ int fd;
+ struct netbuf *svcaddr;
+ char *netid[] = { "tcp6", "tcp" };
+ int i, lastnetid = (sizeof (netid)/sizeof (netid[0])) - 1;
+
+ svcaddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
+ if (! svcaddr)
+ return (FALSE);
+ svcaddr->maxlen = 32;
+ svcaddr->len = 32;
+ svcaddr->buf = (char *)malloc(32);
+ if (! svcaddr->buf) {
+ free(svcaddr);
+ return (FALSE);
+ }
+
+ for (i = 0; i <= lastnetid; i++) {
+ fd = RPC_ANYFD;
+ if ((nconf = getnetconfigent(netid[i])) == NULL) {
+ if (i != lastnetid)
+ continue;
+ logprintf("ypxfr: tcp transport not supported\n");
+ free(svcaddr->buf);
+ free(svcaddr);
+ return (FALSE);
+ }
+ if (rpcb_getaddr(YPPROG, master_prog_vers, nconf, svcaddr,
+ master) == FALSE) {
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ logprintf("ypxfr: could not get %s address\n", master);
+ free(svcaddr->buf);
+ free(svcaddr);
+ return (FALSE);
+ }
+ if ((domb.dom_client = __nis_clnt_create(fd, nconf, 0, svcaddr,
+ 0, YPPROG, master_prog_vers, recvsiz, 0)) == 0) {
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ clnt_pcreateerror(
+ "ypxfr (get_map) - TCP channel create failure");
+ *pushstat = YPPUSH_RPC;
+ free(svcaddr->buf);
+ free(svcaddr);
+ return (FALSE);
+ }
+ break;
+ }
+
+ entry_count = 0;
+ if (master_prog_vers == YPVERS) {
+ allreq.domain = source;
+ allreq.map = map;
+ cbinfo.foreach = ypall_callback;
+ tmpstat = 0;
+ cbinfo.data = (char *)&tmpstat;
+
+ s = clnt_call(domb.dom_client, YPPROC_ALL,
+ (xdrproc_t)xdr_ypreq_nokey,
+ (char *)&allreq, (xdrproc_t)xdr_ypall, (char *)&cbinfo,
+ tcp_timeout);
+
+ if (tmpstat == 0) {
+
+ if (s == RPC_SUCCESS) {
+ retval = TRUE;
+ } else {
+ clnt_perror(domb.dom_client,
+ "ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
+ *pushstat = YPPUSH_RPC;
+ }
+
+ } else {
+ *pushstat = tmpstat;
+ }
+
+ } else
+ retval = FALSE; /* barf again at YPOLDVERS */
+cleanup:
+ clnt_destroy(domb.dom_client);
+ return (retval);
+}
+
+/*
+ * This sticks each key-value pair into the current map. It returns FALSE as
+ * long as it wants to keep getting called back, and TRUE on error conditions
+ * and "No more k-v pairs".
+ */
+int
+ypall_callback(status, key, kl, val, vl, pushstat)
+ int status;
+ char *key;
+ int kl;
+ char *val;
+ int vl;
+ int *pushstat;
+{
+ datum keydat;
+ datum valdat;
+ datum test;
+
+ if (status != YP_TRUE) {
+
+ if (status != YP_NOMORE) {
+ logprintf(
+ "Error from ypserv on %s (ypall_callback) = %s.\n",
+ master, yperr_string(ypprot_err(status)));
+ *pushstat = map_yperr_to_pusherr(status);
+ }
+
+ return (TRUE);
+ }
+
+ keydat.dptr = key;
+ keydat.dsize = kl;
+ valdat.dptr = val;
+ valdat.dsize = vl;
+ entry_count++;
+/* way too many fetches */
+
+#ifdef PARANOID
+ test = dbm_fetch(db, keydat);
+ if (test.dptr != NULL) {
+ logprintf("Duplicate key %s in map %s\n", key, map);
+ *pushstat = YPPUSH_DBM;
+ return (TRUE);
+ }
+#endif /* PARANOID */
+ if (dbm_store(db, keydat, valdat, 0) < 0) {
+ logprintf(
+ "Can't do dbm store into temp map %s.\n", map);
+ *pushstat = YPPUSH_DBM;
+ return (TRUE);
+ }
+#ifdef PARANOID
+ test = dbm_fetch(db, keydat);
+ if (test.dptr == NULL) {
+ logprintf("Key %s was not inserted into dbm file %s\n",
+ key, map);
+ *pushstat = YPPUSH_DBM;
+ return (TRUE);
+ }
+#endif /* PARANOID */
+
+ if (dbm_error(db)) {
+ logprintf("Key %s dbm_error raised in file %s\n",
+ key, map);
+ *pushstat = YPPUSH_DBM;
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * This maps a YP_xxxx error code into a YPPUSH_xxxx error code
+ */
+int
+map_yperr_to_pusherr(yperr)
+ int yperr;
+{
+ int reason;
+
+ switch (yperr) {
+
+ case YP_NOMORE:
+ reason = YPPUSH_SUCC;
+ break;
+
+ case YP_NOMAP:
+ reason = YPPUSH_NOMAP;
+ break;
+
+ case YP_NODOM:
+ reason = YPPUSH_NODOM;
+ break;
+
+ case YP_NOKEY:
+ reason = YPPUSH_YPERR;
+ break;
+
+ case YP_BADARGS:
+ reason = YPPUSH_BADARGS;
+ break;
+
+ case YP_BADDB:
+ reason = YPPUSH_YPERR;
+ break;
+
+ default:
+ reason = YPPUSH_XFRERR;
+ break;
+ }
+
+ return (reason);
+}
+
+/*
+ * This writes the last-modified and master entries into the new dbm file
+ */
+bool
+add_private_entries(pname)
+ char *pname;
+{
+ datum key;
+ datum val;
+
+ if (!fake_master_version) {
+ key.dptr = yp_last_modified;
+ key.dsize = yp_last_modified_sz;
+ val.dptr = master_ascii_version;
+ val.dsize = strlen(master_ascii_version);
+
+ if (dbm_store(db, key, val, 1) < 0) {
+ logprintf(
+ "Can't do dbm store into temp map %s.\n",
+ pname);
+ return (FALSE);
+ }
+ entry_count++;
+ }
+
+ if (master_name) {
+ key.dptr = yp_master_name;
+ key.dsize = yp_master_name_sz;
+ val.dptr = master_name;
+ val.dsize = strlen(master_name);
+ if (dbm_store(db, key, val, 1) < 0) {
+ logprintf(
+ "Can't do dbm store into temp map %s.\n",
+ pname);
+ return (FALSE);
+ }
+ entry_count++;
+ }
+
+ if (interdomain_map) {
+ key.dptr = yp_interdomain;
+ key.dsize = yp_interdomain_sz;
+ val.dptr = interdomain_value;
+ val.dsize = interdomain_sz;
+ if (dbm_store(db, key, val, 1) < 0) {
+ logprintf(
+ "Can't do dbm store into temp map %s.\n",
+ pname);
+ return (FALSE);
+ }
+ entry_count++;
+ }
+
+ if (secure_map) {
+ key.dptr = yp_secure;
+ key.dsize = yp_secure_sz;
+ val.dptr = yp_secure;
+ val.dsize = yp_secure_sz;
+ if (dbm_store(db, key, val, 1) < 0) {
+ logprintf(
+ "Can't do dbm store into temp map %s.\n",
+ pname);
+ return (FALSE);
+ }
+ entry_count++;
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * This sends a YPPROC_CLEAR message to the local ypserv process.
+ */
+bool
+send_ypclear(pushstat)
+ int *pushstat;
+{
+ struct dom_binding domb;
+ char local_host_name[256];
+ unsigned int progvers;
+ int status;
+
+ if (gethostname(local_host_name, 256)) {
+ logprintf("Can't get local machine name.\n");
+ *pushstat = YPPUSH_RSRC;
+ return (FALSE);
+ }
+
+ if (!bind_to_server(local_host_name, &domb,
+ &progvers, &status)) {
+ *pushstat = YPPUSH_CLEAR;
+ return (FALSE);
+ }
+
+ if ((enum clnt_stat) clnt_call(domb.dom_client,
+ YPPROC_CLEAR, xdr_void, 0, xdr_void, 0,
+ udp_timeout) != RPC_SUCCESS) {
+ logprintf(
+ "Can't send ypclear message to ypserv on the local machine.\n");
+ xfr_exit(YPPUSH_CLEAR);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * This decides if send_callback has to get called, and does the process exit.
+ */
+void
+xfr_exit(status)
+ int status;
+{
+ if (callback) {
+ send_callback(&status);
+ }
+
+ if (status == YPPUSH_SUCC) {
+#ifdef TREEPUSH
+ if (treepush) {
+ if (debug)
+ execlp("./yppush", "yppush", "-T", map, 0);
+ execlp("/usr/etc/yp/yppush", "yppush", "-T", map, 0);
+ perror("yppush");
+ }
+#endif
+ exit(0);
+ } else {
+ exit(1);
+ }
+}
+
+/*
+ * This sets up a UDP connection to the yppush process which contacted our
+ * parent ypserv, and sends him a status on the requested transfer.
+ */
+void
+send_callback(status)
+ int *status;
+{
+ struct yppushresp_xfr resp;
+ struct dom_binding domb;
+
+ resp.transid = (unsigned long) atoi(tid);
+ resp.status = (unsigned long) *status;
+
+ udp_timeout.tv_sec = CALLTIMEOUT;
+
+ if ((domb.dom_client = __yp_clnt_create_rsvdport(pushhost,
+ (ulong_t)atoi(proto),
+ YPPUSHVERS,
+ 0, 0, 0)) == NULL) {
+ *status = YPPUSH_RPC;
+ return;
+ }
+
+ if ((enum clnt_stat) clnt_call(domb.dom_client,
+ YPPUSHPROC_XFRRESP, (xdrproc_t)xdr_yppushresp_xfr,
+ (char *)&resp, xdr_void, 0,
+ udp_timeout) != RPC_SUCCESS) {
+ *status = YPPUSH_RPC;
+ return;
+ }
+}
+
+/*
+ * FUNCTION: is_yptol_mode();
+ *
+ * DESCRIPTION: Determines if we should run in N2L or traditional mode based
+ * on the presence of the N2L mapping file.
+ *
+ * This is a copy of a function from libnisdb. If more than this
+ * one function become required it may be worth linking the
+ * entire lib.
+ *
+ * INPUTS: Nothing
+ *
+ * OUTPUTS: TRUE = Run in N2L mode
+ * FALSE = Run in traditional mode.
+ */
+bool_t
+is_yptol_mode()
+{
+ struct stat filestat;
+
+ if (stat(NTOL_MAP_FILE, &filestat) != -1)
+ return (TRUE);
+
+ return (FALSE);
+}
diff --git a/usr/src/cmd/ypcmd/ypxfr_1perday.sh b/usr/src/cmd/ypcmd/ypxfr_1perday.sh
new file mode 100644
index 0000000000..deb5138c22
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfr_1perday.sh
@@ -0,0 +1,41 @@
+#! /bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyr 1990 Sun Microsystems, Inc.
+#ident "%Z%%M% %I% %E% SMI"
+#
+# ypxfr_1perday.sh - Do daily NIS map check/updates
+#
+
+PATH=/bin:/usr/bin:/usr/lib/netsvc/yp:$PATH
+export PATH
+
+# set -xv
+ypxfr group.byname
+ypxfr group.bygid
+ypxfr protocols.byname
+ypxfr protocols.bynumber
+ypxfr networks.byname
+ypxfr networks.byaddr
+ypxfr services.byname
+ypxfr ypservers
diff --git a/usr/src/cmd/ypcmd/ypxfr_1perhour.sh b/usr/src/cmd/ypcmd/ypxfr_1perhour.sh
new file mode 100644
index 0000000000..8903fc2e67
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfr_1perhour.sh
@@ -0,0 +1,35 @@
+#! /bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyr 1990 Sun Microsystems, Inc.
+#ident "%Z%%M% %I% %E% SMI"
+#
+# ypxfr_1perhour.sh - Do hourly NIS map check/updates
+#
+
+PATH=/bin:/usr/bin:/usr/lib/netsvc/yp:$PATH
+export PATH
+
+# set -xv
+ypxfr passwd.byname
+ypxfr passwd.byuid
diff --git a/usr/src/cmd/ypcmd/ypxfr_2perday.sh b/usr/src/cmd/ypcmd/ypxfr_2perday.sh
new file mode 100644
index 0000000000..674f712e60
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfr_2perday.sh
@@ -0,0 +1,41 @@
+#! /bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyr 1990 Sun Microsystems, Inc.
+#ident "%Z%%M% %I% %E% SMI"
+#
+# ypxfr_2perday.sh - Do twice-daily NIS map check/updates
+#
+
+PATH=/bin:/usr/bin:/usr/lib/netsvc/yp:$PATH
+export PATH
+
+# set -xv
+ypxfr hosts.byname
+ypxfr hosts.byaddr
+ypxfr ethers.byaddr
+ypxfr ethers.byname
+ypxfr netgroup
+ypxfr netgroup.byuser
+ypxfr netgroup.byhost
+ypxfr mail.aliases
diff --git a/usr/src/cmd/ypcmd/ypxfrd.x b/usr/src/cmd/ypcmd/ypxfrd.x
new file mode 100644
index 0000000000..6854aceb1b
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfrd.x
@@ -0,0 +1,100 @@
+%/*
+% * CDDL HEADER START
+% *
+% * The contents of this file are subject to the terms of the
+% * Common Development and Distribution License, Version 1.0 only
+% * (the "License"). You may not use this file except in compliance
+% * with the License.
+% *
+% * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% * or http://www.opensolaris.org/os/licensing.
+% * See the License for the specific language governing permissions
+% * and limitations under the License.
+% *
+% * When distributing Covered Code, include this CDDL HEADER in each
+% * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% * If applicable, add the following below this CDDL HEADER, with the
+% * fields enclosed by brackets "[]" replaced with your own identifying
+% * information: Portions Copyright [yyyy] [name of copyright owner]
+% *
+% * CDDL HEADER END
+% *
+% * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
+% * Use is subject to license terms.
+% */
+%
+%#pragma ident "%Z%%M% %I% %E% SMI"
+%
+%/*
+% * This is NOT source code!
+% * DO NOT EDIT THIS FILE!
+% */
+
+const PBLEN = 1024;
+const DBLEN = 4096;
+enum answer {OK,GETDBM_EOF,GETDBM_ERROR};
+
+
+typedef opaque pagblock[PBLEN];
+typedef opaque dirblock[DBLEN];
+typedef string pathname<1024>;
+struct hosereq{
+pathname map;
+pathname domain;
+};
+
+struct pagdat {
+int blkno;
+pagblock blkdat;
+};
+
+struct dirdat {
+int blkno;
+dirblock blkdat;
+};
+
+
+
+union pag switch (answer status){
+case OK:
+ pagdat ok;
+
+default:
+ void;
+};
+
+struct paglist {
+ struct pag d;
+ struct paglist *next;
+};
+
+union dir switch (answer status){
+case OK:
+ dirdat ok;
+
+default:
+ void;
+};
+
+
+struct dirlist {
+ struct dir d;
+ struct dirlist *next;
+};
+struct du {
+struct paglist p;
+struct dirlist d;
+
+};
+union dbmfyl switch (answer status){
+case OK:
+ struct du ok;
+default :
+ void;
+};
+
+program YPXFRD {
+ version V1{
+ dbmfyl getdbm(hosereq)=1;
+ }=1;
+}=100069;
diff --git a/usr/src/cmd/ypcmd/ypxfrd_client.c b/usr/src/cmd/ypcmd/ypxfrd_client.c
new file mode 100644
index 0000000000..0bbc917ba6
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfrd_client.c
@@ -0,0 +1,301 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <errno.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <rpc/rpc.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include "ypxfrd.h"
+#include <ndbm.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/nis.h>
+
+#include <sys/isa_defs.h> /* for ENDIAN defines */
+
+#if defined(_LITTLE_ENDIAN)
+#define DOSWAB 1
+#endif
+
+static struct timeval TIMEOUT = {25, 0};
+static DBM *db;
+
+extern bool secure_map;
+
+/* delete the dbm file with name file */
+static
+dbm_deletefile(file)
+char *file;
+{
+ char pag1[MAXPATHLEN];
+ char dir1[MAXPATHLEN];
+ int err;
+ strcpy(pag1, file);
+ strcat(pag1, ".pag");
+ strcpy(dir1, file);
+ strcat(dir1, ".dir");
+ err = 0;
+ if (unlink(pag1) < 0) {
+ perror("unlinkpag");
+ err = -1;
+ }
+
+ if (unlink(dir1) < 0) {
+ perror("unlinkdir");
+ return (-1);
+ }
+ return (err);
+}
+
+/* xdr just the .pag file of a dbm file */
+static bool_t
+xdr_pages(xdrs, objp)
+ XDR *xdrs;
+{
+ static struct pag res;
+ struct pag *PAG;
+#ifdef DOSWAB
+ short *s;
+ int i;
+#endif
+ bool_t more;
+ bool_t goteof;
+
+ goteof = FALSE;
+ if (!xdr_pag(xdrs, &res))
+ return (FALSE);
+ PAG = &res;
+ while (1) {
+ if (PAG->status == OK) {
+#ifdef DOSWAB
+ s = (short *)PAG->pag_u.ok.blkdat;
+ s[0] = ntohs(s[0]);
+ for (i = 1; i <= s[0]; i++)
+ s[i] = ntohs(s[i]);
+#endif
+ errno = 0;
+ lseek(db->dbm_pagf,
+ PAG->pag_u.ok.blkno * PBLKSIZ, L_SET);
+ if (errno != 0) {
+ perror("seek");
+ exit(-1);
+ }
+ if (write(db->dbm_pagf,
+ PAG->pag_u.ok.blkdat, PBLKSIZ) < 0) {
+ perror("write");
+ exit(-1);
+ }
+ } else if (PAG->status == GETDBM_ERROR) {
+ printf("clnt call getpag GETDBM_ERROR\n");
+ exit(-1);
+ } else if (PAG->status == GETDBM_EOF)
+ goteof = TRUE;
+ if (!xdr_bool(xdrs, &more))
+ return (FALSE);
+ if (more == FALSE)
+ return (goteof);
+ if (!xdr_pag(xdrs, &res))
+ return (FALSE);
+ }
+}
+/* xdr just the .dir part of a dbm file */
+static bool_t
+xdr_dirs(xdrs, objp)
+ XDR *xdrs;
+{
+ static struct dir res;
+ struct dir *DIR;
+ bool_t more;
+ bool_t goteof;
+
+ goteof = FALSE;
+ if (!xdr_dir(xdrs, &res))
+ return (FALSE);
+ DIR = &res;
+ while (1) {
+ if (DIR->status == OK) {
+ errno = 0;
+ lseek(db->dbm_dirf,
+ DIR->dir_u.ok.blkno * DBLKSIZ, L_SET);
+ if (errno != 0) {
+ perror("seek");
+ exit(-1);
+ }
+ if (write(db->dbm_dirf,
+ DIR->dir_u.ok.blkdat, DBLKSIZ) < 0) {
+ perror("write");
+ exit(-1);
+ }
+ } else if (DIR->status == GETDBM_ERROR) {
+ printf("clnt call getdir GETDBM_ERROR\n");
+ exit(-1);
+ } else if (DIR->status == GETDBM_EOF)
+ goteof = TRUE;
+ if (!xdr_bool(xdrs, &more))
+ return (FALSE);
+ if (more == FALSE)
+ return (goteof);
+ if (!xdr_dir(xdrs, &res))
+ return (FALSE);
+ }
+}
+
+/*
+ * xdr a dbm file from ypxfrd
+ * note that if the client or server do not support ndbm
+ * we may not use this optional protocol
+ */
+
+xdr_myfyl(xdrs, objp)
+ XDR *xdrs;
+ int *objp;
+{
+ if (!xdr_answer(xdrs, (answer *)objp))
+ return (FALSE);
+
+ if (*objp != OK)
+ return (TRUE);
+
+ if (!xdr_pages(xdrs, NULL))
+ return (FALSE);
+
+ if (!xdr_dirs(xdrs, NULL))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+ypxfrd_getdbm(tempmap, master, domain, map)
+ char *tempmap;
+ char *master;
+ char *domain;
+ char *map;
+{
+ hosereq rmap;
+ CLIENT *clnt;
+ int res;
+ int recvsiz = 24 * 1024;
+ struct netconfig *nconf;
+ int fd;
+ struct netbuf *svcaddr;
+ struct t_bind *tbind;
+ char *netid[] = { "tcp6", "tcp" };
+ int i, lastnetid = (sizeof (netid)/sizeof (netid[0])) - 1;
+
+ for (i = 0; i <= lastnetid; i++) {
+ if ((nconf = getnetconfigent(netid[i])) == NULL) {
+ if (i != lastnetid)
+ continue;
+ logprintf("ypxfr: tcp transport not supported\n");
+ return (-1);
+ }
+ if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ logprintf("ypxfr: TLI problems\n");
+ return (-1);
+ }
+ if (secure_map == TRUE) {
+ if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd,
+ NULL) == -1) {
+ (void) close(fd);
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ logprintf(
+ "ypxfr: cannot bind to reserved port for %s\n%s\n",
+ netid[i], netdir_sperror(""));
+ return (-1);
+ }
+ }
+
+ if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) ==
+ NULL) {
+ (void) close(fd);
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ logprintf("ypxfr: TLI problems\n");
+ return (-1);
+ }
+ svcaddr = &(tbind->addr);
+ if (rpcb_getaddr(YPXFRD, 1, nconf, svcaddr, master)
+ == FALSE) {
+ (void) t_free((char *)tbind, T_BIND);
+ (void) close(fd);
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ logprintf("ypxfr: couldnot get %s address\n", master);
+ return (-1);
+ }
+ if ((clnt = __nis_clnt_create(fd, nconf, 0, svcaddr, 0,
+ YPXFRD, 1, recvsiz, 0)) == 0) {
+ (void) t_free((char *)tbind, T_BIND);
+ (void) close(fd);
+ freenetconfigent(nconf);
+ if (i != lastnetid)
+ continue;
+ clnt_pcreateerror(
+ "ypxfr (get_map) - TCP channel create failure");
+ return (-1);
+ }
+ (void) t_free((char *)tbind, T_BIND);
+ break;
+ }
+ (void) CLNT_CONTROL(clnt, CLSET_FD_CLOSE, (char *)NULL);
+
+ rmap.map = map;
+ rmap.domain = domain;
+ memset((char *) &res, 0, sizeof (res));
+ db = dbm_open(tempmap, O_RDWR + O_CREAT + O_TRUNC, 0777);
+ if (db == NULL) {
+ logprintf("dbm_open failed %s\n", tempmap);
+ perror(tempmap);
+ return (-2);
+ }
+
+ if (clnt_call(clnt, getdbm, xdr_hosereq, (char *)&rmap, xdr_myfyl,
+ (char *)&res, TIMEOUT) != RPC_SUCCESS) {
+ logprintf("clnt call to ypxfrd getdbm failed.\n");
+ clnt_perror(clnt, "getdbm");
+ dbm_deletefile(tempmap);
+ return (-3);
+ }
+ if (res != OK) {
+ logprintf("clnt call %s ypxfrd getdbm NOTOK %s %s code=%d\n",
+ master, domain, map, res);
+ dbm_deletefile(tempmap);
+ return (-4);
+ }
+ return (0);
+
+}
diff --git a/usr/src/cmd/ypcmd/ypxfrd_server.c b/usr/src/cmd/ypcmd/ypxfrd_server.c
new file mode 100644
index 0000000000..24fbb2211e
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfrd_server.c
@@ -0,0 +1,438 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ndbm.h>
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include "ypxfrd.h"
+#include "ypsym.h"
+#include "ypdefs.h"
+/*
+ * Because this code hacks into DBM underneath its API it can't use the N2L
+ * shim in it's normal way. It thus includes shim.h instead of shim_hooks.h
+ * and has knowledge of shim internals. While copying the DBM files it does
+ * not lock them. This reflects the behavior of the pre N2L code.
+ */
+#include "shim.h"
+#include "yptol.h"
+
+#if (defined(vax) || defined(i386))
+#define DOSWAB 1
+#endif
+
+USE_YP_SECURE
+
+/* per connection stuff */
+struct mycon {
+ map_ctrl *map;
+ int lblk;
+ int firstd;
+ datum key;
+};
+
+bool_t xdr_myfyl(XDR *xdrs, struct mycon *objp);
+bool_t xdr_pages(XDR *xdrs, struct mycon *m);
+bool_t xdr_dirs(XDR *xdrs, struct mycon *m);
+
+int mygetdir(char *block, int *no, struct mycon *m);
+int mygetpage(char *block, int *pageno, struct mycon *m);
+
+datum mydbm_topkey(DBM *db, datum okey);
+datum dbm_do_nextkey();
+datum shim_dbm_do_nextkey();
+
+extern void get_secure_nets(char *);
+extern int check_secure_net_ti(struct netbuf *, char *);
+extern int _main(int, char **);
+
+int
+main(int argc, char **argv)
+{
+ int connmaxrec = RPC_MAXDATASIZE;
+
+ /* load up the securenet file */
+ get_secure_nets(argv[0]);
+
+ /*
+ * Set non-blocking mode and maximum record size for
+ * connection oriented RPC transports.
+ */
+ if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
+ syslog(LOG_INFO|LOG_DAEMON,
+ "unable to set maximum RPC record size");
+ }
+
+ /* Initialize file locking etc. */
+ if (!init_lock_system(TRUE))
+ /* An detailed error will already have been logged */
+ exit(-1);
+
+ return (_main(argc, argv));
+}
+
+/*
+ * In yptol mode we may start a cache update thread within a child process.
+ * It is thus important that child processes do not exit, killing any such
+ * threads, before the thread has completed. They must thus call this version
+ * of the exit() function.
+ */
+void
+yptol_exit(int status)
+{
+ if (yptol_mode) {
+ thr_join(0, NULL, NULL);
+ }
+ exit(status);
+}
+
+dbmfyl *
+getdbm_1_svc(hosereq *argp, struct svc_req *rqstp)
+{
+ static dbmfyl result;
+ char path[MAXNAMLEN + 1];
+ SVCXPRT *xprt;
+ int pid;
+ int res;
+ struct mycon m;
+ char *ypname = "ypxfrd";
+ struct netbuf *nbuf;
+ sa_family_t af;
+ in_port_t port;
+
+ xprt = rqstp->rq_xprt;
+
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
+ /*
+ * Build up path name. If we are working in N2L mode also conv
+ * to the new N2L style mapname.
+ *
+ * Do not allow any path as a domain name or map name.
+ */
+ if ((strchr(argp->domain, '/') != NULL) ||
+ (strchr(argp->map, '/') != NULL) ||
+ (!ypmkfilename(argp->domain, argp->map, (char *)&path))) {
+ res = GETDBM_ERROR;
+ if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
+ (caddr_t)&res)) {
+ svcerr_systemerr(rqstp->rq_xprt);
+ }
+ return (NULL);
+ }
+
+ pid = fork1();
+ if (pid < 0) {
+ perror("fork");
+
+ res = GETDBM_ERROR;
+ if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
+ (caddr_t)&res)) {
+ svcerr_systemerr(rqstp->rq_xprt);
+ }
+ return (NULL);
+ }
+ if (pid != 0)
+ return (NULL);
+
+ m.map = (map_ctrl *)shim_dbm_open(path, 0, 0);
+ if (m.map == NULL) {
+ perror(path);
+ res = GETDBM_ERROR;
+ if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
+ (caddr_t)&res)) {
+ svcerr_systemerr(rqstp->rq_xprt);
+ }
+ yptol_exit(0);
+ return (NULL);
+ }
+
+ /* Do the security thing */
+ if ((nbuf = svc_getrpccaller(xprt)) == 0) {
+ res = GETDBM_ERROR;
+ if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
+ svcerr_systemerr(xprt);
+ }
+ shim_dbm_close((DBM *)m.map);
+ yptol_exit(0);
+ return (NULL);
+ }
+ if (!check_secure_net_ti(nbuf, ypname)) {
+ res = GETDBM_ERROR;
+ if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
+ svcerr_systemerr(xprt);
+ }
+ shim_dbm_close((DBM *)m.map);
+ yptol_exit(1);
+ return (NULL);
+ }
+
+ af = ((struct sockaddr_storage *)nbuf->buf)->ss_family;
+ port = (af == AF_INET6) ?
+ ((struct sockaddr_in6 *)nbuf->buf)->sin6_port :
+ ((struct sockaddr_in *)nbuf->buf)->sin_port;
+
+ if ((af == AF_INET || af == AF_INET6) &&
+ (ntohs(port) > IPPORT_RESERVED)) {
+ datum key, val;
+
+ key.dptr = yp_secure;
+ key.dsize = yp_secure_sz;
+ val = shim_dbm_fetch((DBM *)m.map, key);
+ if (val.dptr != NULL) {
+ res = GETDBM_ERROR;
+ if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
+ svcerr_systemerr(xprt);
+ }
+ shim_dbm_close((DBM *)m.map);
+ yptol_exit(1);
+ return (NULL);
+ }
+ }
+
+ /* OK, we're through */
+ m.key = shim_dbm_firstkey((DBM *)m.map);
+
+ m.lblk = -1;
+ m.firstd = 0;
+
+ if (!svc_sendreply(rqstp->rq_xprt, xdr_myfyl, (caddr_t)&m)) {
+ svcerr_systemerr(rqstp->rq_xprt);
+ }
+ shim_dbm_close((DBM *)m.map);
+ yptol_exit(0);
+
+ return (&result);
+}
+
+bool_t
+xdr_myfyl(XDR *xdrs, struct mycon *objp)
+{
+ int ans = OK;
+
+ if (!xdr_answer(xdrs, (answer *) &ans))
+ return (FALSE);
+ if (!xdr_pages(xdrs, objp))
+ return (FALSE);
+ if (!xdr_dirs(xdrs, objp))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+bool_t
+xdr_pages(XDR *xdrs, struct mycon *m)
+{
+ static struct pag res;
+ bool_t false = FALSE;
+ bool_t true = TRUE;
+#ifdef DOSWAB
+ short *s;
+ int i;
+ int cnt;
+#endif
+ res.status = mygetpage(res.pag_u.ok.blkdat, &(res.pag_u.ok.blkno), m);
+
+#ifdef DOSWAB
+ s = (short *)res.pag_u.ok.blkdat;
+ cnt = s[0];
+ for (i = 0; i <= cnt; i++)
+ s[i] = ntohs(s[i]);
+#endif
+
+ if (!xdr_pag(xdrs, &res))
+ return (FALSE);
+
+ while (res.status == OK) {
+ if (!xdr_bool(xdrs, &true))
+ return (FALSE);
+ res.status = mygetpage(res.pag_u.ok.blkdat,
+ &(res.pag_u.ok.blkno), m);
+
+#ifdef DOSWAB
+ s = (short *)res.pag_u.ok.blkdat;
+ cnt = s[0];
+ for (i = 0; i <= cnt; i++)
+ s[i] = ntohs(s[i]);
+#endif
+
+ if (!xdr_pag(xdrs, &res))
+ return (FALSE);
+ }
+
+ return (xdr_bool(xdrs, &false));
+}
+
+int
+mygetdir(char *block, int *no, struct mycon *m)
+{
+ int status;
+ int len;
+
+ if (m->firstd == 0) {
+ lseek(m->map->entries->dbm_dirf, 0, 0);
+ m->firstd = 1;
+ } else
+ m->firstd++;
+
+ len = read(m->map->entries->dbm_dirf, block, DBLKSIZ);
+ *no = (m->firstd) - 1;
+ status = OK;
+
+ /*
+ * printf("dir block %d\n", (m->firstd) - 1);
+ */
+
+ if (len < 0) {
+ perror("read directory");
+ status = GETDBM_ERROR;
+ } else if (len == 0) {
+ status = GETDBM_EOF;
+ /*
+ * printf("dir EOF\n");
+ */
+ }
+ return (status);
+}
+
+bool_t
+xdr_dirs(XDR *xdrs, struct mycon *m)
+{
+ static struct dir res;
+ bool_t false = FALSE;
+ bool_t true = TRUE;
+
+ res.status = mygetdir(res.dir_u.ok.blkdat, &(res.dir_u.ok.blkno), m);
+
+ if (!xdr_dir(xdrs, &res))
+ return (FALSE);
+
+ while (res.status == OK) {
+ if (!xdr_bool(xdrs, &true))
+ return (FALSE);
+ res.status = mygetdir(res.dir_u.ok.blkdat,
+ &(res.dir_u.ok.blkno), m);
+ if (!xdr_dir(xdrs, &res))
+ return (FALSE);
+ }
+
+ return (xdr_bool(xdrs, &false));
+}
+
+int
+mygetpage(char *block, int *pageno, struct mycon *m)
+{
+
+ for (; m->key.dptr;
+ m->key = shim_dbm_do_nextkey((DBM *)m->map, m->key)) {
+
+ if (m->map->entries->dbm_pagbno != m->lblk) {
+ /*
+ * printf("block=%d lblk=%d\n",
+ * m->map->entries->dbm_pagbno,
+ * m->lblk);
+ */
+ m->lblk = m->map->entries->dbm_pagbno;
+ *pageno = m->lblk;
+ memmove(block, m->map->entries->dbm_pagbuf, PBLKSIZ);
+ /* advance key on first try */
+ m->key = mydbm_topkey(m->map->entries, m->key);
+ m->key = shim_dbm_do_nextkey((DBM *)m->map, m->key);
+ return (OK);
+ }
+ }
+ /*
+ * printf("EOF\n");
+ */
+ return (GETDBM_EOF);
+}
+
+datum
+mydbm_topkey(DBM *db, datum okey)
+{
+ datum ans;
+ datum tmp;
+ register char *buf;
+ int n;
+ register short *sp;
+ register t;
+ datum item;
+ register m;
+ register char *p1, *p2;
+
+ buf = db->dbm_pagbuf;
+ sp = (short *)buf;
+ /* find the maximum key in cmpdatum order */
+
+ if ((unsigned)0 >= sp[0]) {
+ return (okey);
+ } else {
+ ans.dptr = buf + sp[1];
+ ans.dsize = PBLKSIZ - sp[1];
+ }
+ for (n = 2; ; n += 2) {
+ if ((unsigned)n >= sp[0]) {
+ if (ans.dptr == NULL) {
+ return (okey);
+ } else {
+ return (ans);
+ }
+ } else {
+ t = PBLKSIZ;
+ if (n > 0)
+ t = sp[n];
+ tmp.dptr = buf + sp[n + 1];
+ tmp.dsize = t - sp[n + 1];
+ }
+
+ m = tmp.dsize;
+ if (m != ans.dsize) {
+ if ((m - ans.dsize) < 0)
+ ans = tmp;
+ } else if (m == 0) {
+ } else {
+ p1 = tmp.dptr;
+ p2 = ans.dptr;
+ do
+ if (*p1++ != *p2++) {
+ if ((*--p1 - *--p2) < 0)
+ ans = tmp;
+ break;
+ }
+ while (--m);
+ }
+ }
+}
diff --git a/usr/src/cmd/ypcmd/ypxfrd_svc.c b/usr/src/cmd/ypcmd/ypxfrd_svc.c
new file mode 100644
index 0000000000..d0e5467ea3
--- /dev/null
+++ b/usr/src/cmd/ypcmd/ypxfrd_svc.c
@@ -0,0 +1,273 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This source was formally rpcgen generated, but has been
+ * checked in.
+ */
+
+#include "ypxfrd.h"
+#include <stdio.h>
+#include <stdlib.h> /* getenv, exit */
+#include <signal.h>
+#include <rpc/pmap_clnt.h> /* for pmap_unset */
+#include <string.h> /* strcmp */
+#include <unistd.h> /* setsid */
+#include <sys/types.h>
+#include <memory.h>
+#include <stropts.h>
+#include <netconfig.h>
+#include <sys/resource.h> /* rlimit */
+#include <syslog.h>
+#include <ndbm.h>
+#include "shim.h"
+#include "yptol.h"
+
+#ifndef SIG_PF
+#define SIG_PF void(*)(int)
+#endif
+
+#ifdef DEBUG
+#define RPC_SVC_FG
+#endif
+
+#define _RPCSVC_CLOSEDOWN 120
+
+/*
+ * Copyr 1989 Sun Micro
+ * #ident "@(#)ypxfrd.x 1.2 00/05/01 SMI"
+ * This is NOT source code!
+ * DO NOT EDIT THIS FILE!
+ */
+static int _rpcpmstart; /* Started by a port monitor ? */
+
+/* States a server can be in wrt request */
+
+#define _IDLE 0
+#define _SERVED 1
+
+static int _rpcsvcstate = _IDLE; /* Set when a request is serviced */
+static int _rpcsvccount = 0; /* Number of requests being serviced */
+
+static void
+_msgout(char *msg)
+{
+#ifdef RPC_SVC_FG
+ if (_rpcpmstart)
+ syslog(LOG_ERR, "%s", msg);
+ else
+ (void) fprintf(stderr, "%s\n", msg);
+#else
+ syslog(LOG_ERR, "%s", msg);
+#endif
+}
+
+static void
+closedown(int sig)
+{
+ if (_rpcsvcstate == _IDLE && _rpcsvccount == 0) {
+ int size;
+ int i, openfd = 0;
+
+ size = svc_max_pollfd;
+ for (i = 0; i < size && openfd < 2; i++)
+ if (svc_pollfd[i].fd >= 0)
+ openfd++;
+ if (openfd <= 1)
+ exit(0);
+ } else
+ _rpcsvcstate = _IDLE;
+
+ (void) signal(SIGALRM, (SIG_PF) closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN/2);
+}
+
+static void
+ypxfrd_1(struct svc_req *rqstp, register SVCXPRT *transp)
+{
+ union {
+ hosereq getdbm_1_arg;
+ } argument;
+ char *result;
+ xdrproc_t _xdr_argument, _xdr_result;
+ char *(*local)(char *, struct svc_req *);
+
+ _rpcsvccount++;
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ (void) svc_sendreply(transp,
+ (xdrproc_t)xdr_void, (char *)NULL);
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+ return;
+
+ case getdbm:
+ _xdr_argument = (xdrproc_t)xdr_hosereq;
+ _xdr_result = (xdrproc_t)xdr_dbmfyl;
+ local = (char *(*)(char *, struct svc_req *)) getdbm_1_svc;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+ return;
+ }
+ (void) memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
+ svcerr_decode(transp);
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+ return;
+ }
+ result = (*local)((char *)&argument, rqstp);
+ if (_xdr_result && result != NULL &&
+ !svc_sendreply(transp, _xdr_result, result)) {
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) {
+ _msgout("unable to free arguments");
+ exit(1);
+ }
+ _rpcsvccount--;
+ _rpcsvcstate = _SERVED;
+}
+
+main()
+{
+ pid_t pid;
+ int i;
+ int stat;
+
+ (void) sigset(SIGPIPE, SIG_IGN);
+
+ /*
+ * If stdin looks like a TLI endpoint, we assume
+ * that we were started by a port monitor. If
+ * t_getstate fails with TBADF, this is not a
+ * TLI endpoint.
+ */
+ if (t_getstate(0) != -1 || t_errno != TBADF) {
+ char *netid;
+ struct netconfig *nconf = NULL;
+ SVCXPRT *transp;
+ int pmclose;
+
+ _rpcpmstart = 1;
+ openlog("ypxfrd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+ if ((netid = getenv("NLSPROVIDER")) == NULL) {
+ /* started from inetd */
+ pmclose = 1;
+ } else {
+ if ((nconf = getnetconfigent(netid)) == NULL)
+ _msgout("cannot get transport info");
+
+ pmclose = (t_getstate(0) != T_DATAXFER);
+ }
+ if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
+ _msgout("cannot create server handle");
+ exit(1);
+ }
+ if (nconf)
+ freenetconfigent(nconf);
+ if (!svc_reg(transp, YPXFRD, V1, ypxfrd_1, 0)) {
+ _msgout("unable to register (YPXFRD, V1).");
+ exit(1);
+ }
+ if (pmclose) {
+ (void) signal(SIGALRM, (SIG_PF) closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN/2);
+ }
+
+ if (yptol_mode) {
+ stat = parseConfig(NULL, NTOL_MAP_FILE);
+ if (stat == 1) {
+ _msgout("NIS to LDAP mapping inactive.");
+ } else if (stat != 0) {
+ _msgout("Aborting after NIS to LDAP "
+ "mapping error.");
+ exit(1);
+ }
+ }
+
+ svc_run();
+ exit(1);
+ /* NOTREACHED */
+ } else {
+#ifndef RPC_SVC_FG
+#pragma weak closefrom
+ extern void closefrom();
+ int size;
+ struct rlimit rl;
+ pid = fork();
+ if (pid < 0) {
+ perror("cannot fork");
+ exit(1);
+ }
+ if (pid)
+ exit(0);
+ closelog();
+ if (closefrom != NULL)
+ closefrom(0);
+ else {
+ rl.rlim_max = 0;
+ getrlimit(RLIMIT_NOFILE, &rl);
+ if ((size = rl.rlim_max) == 0)
+ exit(1);
+ for (i = 0; i < size; i++)
+ (void) close(i);
+ }
+ i = open("/dev/null", 2);
+ (void) dup2(i, 1);
+ (void) dup2(i, 2);
+ openlog("ypxfrd", LOG_NDELAY|LOG_PID, LOG_DAEMON);
+ setsid();
+#endif
+ }
+
+ if (yptol_mode) {
+ stat = parseConfig(NULL, NTOL_MAP_FILE);
+ if (stat == 1) {
+ _msgout("NIS to LDAP mapping inactive.");
+ } else if (stat != 0) {
+ _msgout("Aborting after NIS to LDAP mapping error.");
+ exit(1);
+ }
+ }
+
+ if (!svc_create(ypxfrd_1, YPXFRD, V1, "visible")) {
+ _msgout("unable to create (YPXFRD, V1) for visible.");
+ exit(1);
+ }
+
+ svc_run();
+ _msgout("svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}