diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/ypcmd | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/ypcmd')
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 */ +} |
