yp_server.c revision 114601
112891Swpaul/*
212891Swpaul * Copyright (c) 1995
312891Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
412891Swpaul *
512891Swpaul * Redistribution and use in source and binary forms, with or without
612891Swpaul * modification, are permitted provided that the following conditions
712891Swpaul * are met:
812891Swpaul * 1. Redistributions of source code must retain the above copyright
912891Swpaul *    notice, this list of conditions and the following disclaimer.
1012891Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1112891Swpaul *    notice, this list of conditions and the following disclaimer in the
1212891Swpaul *    documentation and/or other materials provided with the distribution.
1312891Swpaul * 3. All advertising materials mentioning features or use of this software
1412891Swpaul *    must display the following acknowledgement:
1512891Swpaul *	This product includes software developed by Bill Paul.
1612891Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1712891Swpaul *    may be used to endorse or promote products derived from this software
1812891Swpaul *    without specific prior written permission.
1912891Swpaul *
2012891Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2112891Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2212891Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2312891Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2412891Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2512891Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2612891Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2712891Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2812891Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2912891Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3012891Swpaul * SUCH DAMAGE.
3112891Swpaul *
3212891Swpaul */
3312891Swpaul
34114601Sobrien#include <sys/cdefs.h>
35114601Sobrien__FBSDID("$FreeBSD: head/usr.sbin/ypserv/yp_server.c 114601 2003-05-03 21:06:42Z obrien $");
3630827Scharnier
3720818Swpaul#include "yp.h"
3812891Swpaul#include "yp_extern.h"
3930827Scharnier#include <dirent.h>
4030827Scharnier#include <errno.h>
4112891Swpaul#include <stdlib.h>
4212891Swpaul#include <sys/stat.h>
4312891Swpaul#include <sys/param.h>
4412891Swpaul#include <sys/types.h>
4512891Swpaul#include <sys/socket.h>
4612891Swpaul#include <netinet/in.h>
4712891Swpaul#include <arpa/inet.h>
4812997Swpaul#include <rpc/rpc.h>
4912891Swpaul
5012891Swpaulint children = 0;
5112891Swpaul
5228042Swpaul#define	MASTER_STRING	"YP_MASTER_NAME"
5328042Swpaul#define	MASTER_SZ	sizeof(MASTER_STRING) - 1
5428042Swpaul#define	ORDER_STRING	"YP_LAST_MODIFIED"
5528042Swpaul#define	ORDER_SZ	sizeof(ORDER_STRING) - 1
5628042Swpaul
5790298Sdesstatic pid_t
5890298Sdesyp_fork(void)
5946186Swpaul{
6046186Swpaul	if (yp_pid != getpid()) {
6146186Swpaul		yp_error("child %d trying to fork!", getpid());
6246186Swpaul		errno = EEXIST;
6346186Swpaul		return(-1);
6446186Swpaul	}
6546186Swpaul
6646186Swpaul	return(fork());
6746186Swpaul}
6846186Swpaul
6914262Swpaul/*
7014262Swpaul * NIS v2 support. This is where most of the action happens.
7114262Swpaul */
7214262Swpaul
7312891Swpaulvoid *
7412891Swpaulypproc_null_2_svc(void *argp, struct svc_req *rqstp)
7512891Swpaul{
7612891Swpaul	static char * result;
7712891Swpaul	static char rval = 0;
7812891Swpaul
7919161Swpaul#ifdef DB_CACHE
8019161Swpaul	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
8119161Swpaul#else
8212891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
8319161Swpaul#endif
8412891Swpaul		return(NULL);
8512891Swpaul
8612891Swpaul	result = &rval;
8712891Swpaul
8812891Swpaul	return((void *) &result);
8912891Swpaul}
9012891Swpaul
9112891Swpaulbool_t *
9212891Swpaulypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
9312891Swpaul{
9412891Swpaul	static bool_t  result;
9512891Swpaul
9619161Swpaul#ifdef DB_CACHE
9719161Swpaul	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
9819161Swpaul#else
9912891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
10019161Swpaul#endif
10112891Swpaul		result = FALSE;
10212891Swpaul		return (&result);
10312891Swpaul	}
10412891Swpaul
10512891Swpaul	if (argp == NULL || yp_validdomain(*argp))
10612891Swpaul		result = FALSE;
10712891Swpaul	else
10812891Swpaul		result = TRUE;
10912891Swpaul
11012891Swpaul	return (&result);
11112891Swpaul}
11212891Swpaul
11312891Swpaulbool_t *
11412891Swpaulypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
11512891Swpaul{
11612891Swpaul	static bool_t  result;
11712891Swpaul
11819161Swpaul#ifdef DB_CACHE
11919161Swpaul	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
12019161Swpaul#else
12112891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
12219161Swpaul#endif
12312891Swpaul		return (NULL);
12412891Swpaul
12512891Swpaul	if (argp == NULL || yp_validdomain(*argp))
12612891Swpaul		return (NULL);
12712891Swpaul	else
12812891Swpaul		result = TRUE;
12912891Swpaul
13012891Swpaul	return (&result);
13112891Swpaul}
13212891Swpaul
13312891Swpaulypresp_val *
13412891Swpaulypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
13512891Swpaul{
13612891Swpaul	static ypresp_val  result;
13712891Swpaul
13814304Swpaul	result.val.valdat_val = "";
13914304Swpaul	result.val.valdat_len = 0;
14019161Swpaul
14119161Swpaul#ifdef DB_CACHE
14219161Swpaul	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
14319161Swpaul#else
14412891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
14519161Swpaul#endif
14612891Swpaul		result.stat = YP_YPERR;
14712891Swpaul		return (&result);
14812891Swpaul	}
14912891Swpaul
15012891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
15112891Swpaul		result.stat = YP_BADARGS;
15212891Swpaul		return (&result);
15312891Swpaul	}
15412891Swpaul
15533250Swpaul	if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) {
15620818Swpaul		result.stat = yp_errno;
15720818Swpaul		return(&result);
15812891Swpaul	}
15912891Swpaul
16020818Swpaul	result.stat = yp_getbykey(&argp->key, &result.val);
16120818Swpaul
16212891Swpaul	/*
16312891Swpaul	 * Do DNS lookups for hosts maps if database lookup failed.
16412891Swpaul	 */
16512891Swpaul
16619161Swpaul#ifdef DB_CACHE
16719161Swpaul	if (result.stat != YP_TRUE &&
16819161Swpaul	    (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) ||
16919161Swpaul	    (strstr(argp->map, "hosts") && do_dns))) {
17019161Swpaul#else
17112891Swpaul	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
17219161Swpaul#endif
17327589Swpaul		char			nbuf[YPMAXRECORD];
17490297Sdes
17520818Swpaul		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
17627589Swpaul		bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len);
17727589Swpaul		nbuf[argp->key.keydat_len] = '\0';
17812891Swpaul
17912891Swpaul		if (debug)
18030827Scharnier			yp_error("doing DNS lookup of %s", nbuf);
18112891Swpaul
18212891Swpaul		if (!strcmp(argp->map, "hosts.byname"))
18327589Swpaul			result.stat = yp_async_lookup_name(rqstp, nbuf);
18412891Swpaul		else if (!strcmp(argp->map, "hosts.byaddr"))
18527589Swpaul			result.stat = yp_async_lookup_addr(rqstp, nbuf);
18612891Swpaul
18720818Swpaul		if (result.stat == YP_TRUE)
18820818Swpaul			return(NULL);
18912891Swpaul	}
19012891Swpaul
19112891Swpaul	return (&result);
19212891Swpaul}
19312891Swpaul
19412891Swpaulypresp_key_val *
19512891Swpaulypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
19612891Swpaul{
19712891Swpaul	static ypresp_key_val  result;
19812891Swpaul
19914304Swpaul	result.val.valdat_val = result.key.keydat_val = "";
20014304Swpaul	result.val.valdat_len = result.key.keydat_len = 0;
20119161Swpaul
20219161Swpaul#ifdef DB_CACHE
20319161Swpaul	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
20419161Swpaul#else
20512891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
20619161Swpaul#endif
20712891Swpaul		result.stat = YP_YPERR;
20812891Swpaul		return (&result);
20912891Swpaul	}
21012891Swpaul
21112891Swpaul	if (argp->domain == NULL) {
21212891Swpaul		result.stat = YP_BADARGS;
21312891Swpaul		return (&result);
21412891Swpaul	}
21512891Swpaul
21633250Swpaul	if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) {
21712891Swpaul		result.stat = yp_errno;
21812891Swpaul		return(&result);
21912891Swpaul	}
22012891Swpaul
22120818Swpaul	result.stat = yp_firstbykey(&result.key, &result.val);
22212891Swpaul
22312891Swpaul	return (&result);
22412891Swpaul}
22512891Swpaul
22612891Swpaulypresp_key_val *
22712891Swpaulypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
22812891Swpaul{
22912891Swpaul	static ypresp_key_val  result;
23012891Swpaul
23114304Swpaul	result.val.valdat_val = result.key.keydat_val = "";
23214304Swpaul	result.val.valdat_len = result.key.keydat_len = 0;
23315426Swpaul
23419161Swpaul#ifdef DB_CACHE
23519161Swpaul	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
23619161Swpaul#else
23712891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
23819161Swpaul#endif
23912891Swpaul		result.stat = YP_YPERR;
24012891Swpaul		return (&result);
24112891Swpaul	}
24212891Swpaul
24312891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
24412891Swpaul		result.stat = YP_BADARGS;
24512891Swpaul		return (&result);
24612891Swpaul	}
24712891Swpaul
24820818Swpaul	if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) {
24912891Swpaul		result.stat = yp_errno;
25012891Swpaul		return(&result);
25112891Swpaul	}
25212891Swpaul
25320818Swpaul	result.key.keydat_len = argp->key.keydat_len;
25420818Swpaul	result.key.keydat_val = argp->key.keydat_val;
25512891Swpaul
25620818Swpaul	result.stat = yp_nextbykey(&result.key, &result.val);
25720818Swpaul
25812891Swpaul	return (&result);
25912891Swpaul}
26012891Swpaul
26190298Sdesstatic void
26290298Sdesypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid,
26390298Sdes    unsigned int prognum, unsigned long port)
26412997Swpaul{
26512997Swpaul	CLIENT *clnt;
26612997Swpaul	int sock = RPC_ANYSOCK;
26712997Swpaul	struct timeval timeout;
26812997Swpaul	yppushresp_xfr ypxfr_resp;
26913375Swpaul	struct rpc_err err;
27012997Swpaul
27113375Swpaul	timeout.tv_sec = 5;
27212997Swpaul	timeout.tv_usec = 0;
27312997Swpaul	addr->sin_port = htons(port);
27412997Swpaul
27519131Swpaul	if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) {
27619131Swpaul		yp_error("%s: %s", inet_ntoa(addr->sin_addr),
27719161Swpaul		  clnt_spcreateerror("failed to establish callback handle"));
27819131Swpaul		return;
27919131Swpaul	}
28012997Swpaul
28112997Swpaul	ypxfr_resp.status = rval;
28212997Swpaul	ypxfr_resp.transid = transid;
28312997Swpaul
28413375Swpaul	/* Turn the timeout off -- we don't want to block. */
28513375Swpaul	timeout.tv_sec = 0;
28695658Sdes	if (clnt_control(clnt, CLSET_TIMEOUT, &timeout) == FALSE)
28713375Swpaul		yp_error("failed to set timeout on ypproc_xfr callback");
28812997Swpaul
28913375Swpaul	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
29013375Swpaul		clnt_geterr(clnt, &err);
29113375Swpaul		if (err.re_status != RPC_SUCCESS &&
29213375Swpaul		    err.re_status != RPC_TIMEDOUT)
29313375Swpaul			yp_error("%s", clnt_sperror(clnt,
29413375Swpaul				"ypxfr callback failed"));
29513375Swpaul	}
29613375Swpaul
29712997Swpaul	clnt_destroy(clnt);
29812997Swpaul	return;
29912997Swpaul}
30012997Swpaul
30115426Swpaul#define YPXFR_RETURN(CODE) 						\
30215426Swpaul	/* Order is important: send regular RPC reply, then callback */	\
30315426Swpaul	result.xfrstat = CODE; 						\
30495658Sdes	svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_ypresp_xfr, &result); \
30515426Swpaul	ypxfr_callback(CODE,rqhost,argp->transid, 			\
30615426Swpaul					argp->prog,argp->port); 	\
30715426Swpaul	return(NULL);
30815426Swpaul
30912891Swpaulypresp_xfr *
31012891Swpaulypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
31112891Swpaul{
31212891Swpaul	static ypresp_xfr  result;
31312997Swpaul	struct sockaddr_in *rqhost;
31424780Swpaul	ypresp_master *mres;
31524780Swpaul	ypreq_nokey mreq;
31612891Swpaul
31713375Swpaul	result.transid = argp->transid;
31813375Swpaul	rqhost = svc_getcaller(rqstp->rq_xprt);
31913375Swpaul
32019161Swpaul#ifdef DB_CACHE
32119161Swpaul	if (yp_access(argp->map_parms.map,
32219161Swpaul			argp->map_parms.domain, (struct svc_req *)rqstp)) {
32319161Swpaul#else
32412891Swpaul	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
32519161Swpaul#endif
32624780Swpaul		YPXFR_RETURN(YPXFR_REFUSED)
32712891Swpaul	}
32812891Swpaul
32924780Swpaul
33012891Swpaul	if (argp->map_parms.domain == NULL) {
33124780Swpaul		YPXFR_RETURN(YPXFR_BADARGS)
33212891Swpaul	}
33312891Swpaul
33412891Swpaul	if (yp_validdomain(argp->map_parms.domain)) {
33524780Swpaul		YPXFR_RETURN(YPXFR_NODOM)
33612891Swpaul	}
33712891Swpaul
33824780Swpaul	/*
33924780Swpaul	 * Determine the master host ourselves. The caller may
34024780Swpaul	 * be up to no good. This has the side effect of verifying
34124780Swpaul	 * that the requested map and domain actually exist.
34224780Swpaul	 */
34324780Swpaul
34424780Swpaul	mreq.domain = argp->map_parms.domain;
34524780Swpaul	mreq.map = argp->map_parms.map;
34624780Swpaul
34724780Swpaul	mres = ypproc_master_2_svc(&mreq, rqstp);
34824780Swpaul
34924780Swpaul	if (mres->stat != YP_TRUE) {
35024780Swpaul		yp_error("couldn't find master for map %s@%s",
35124780Swpaul						argp->map_parms.map,
35224780Swpaul						argp->map_parms.domain);
35324780Swpaul		yp_error("host at %s (%s) may be pulling my leg",
35424780Swpaul						argp->map_parms.peer,
35524780Swpaul						inet_ntoa(rqhost->sin_addr));
35624780Swpaul		YPXFR_RETURN(YPXFR_REFUSED)
35724780Swpaul	}
35824780Swpaul
35990297Sdes	switch (yp_fork()) {
36012891Swpaul	case 0:
36112891Swpaul	{
36212891Swpaul		char g[11], t[11], p[11];
36312891Swpaul		char ypxfr_command[MAXPATHLEN + 2];
36412891Swpaul
36580184Skris		snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC);
36680184Skris		snprintf (t, sizeof(t), "%u", argp->transid);
36780184Skris		snprintf (g, sizeof(g), "%u", argp->prog);
36880184Skris		snprintf (p, sizeof(p), "%u", argp->port);
36922321Swpaul		if (debug) {
37012997Swpaul			close(0); close(1); close(2);
37122321Swpaul		}
37212997Swpaul		if (strcmp(yp_dir, _PATH_YP)) {
37314304Swpaul			execl(ypxfr_command, "ypxfr",
37414304Swpaul			"-d", argp->map_parms.domain,
37524780Swpaul		      	"-h", mres->peer,
37614304Swpaul			"-p", yp_dir, "-C", t,
37714304Swpaul		      	g, inet_ntoa(rqhost->sin_addr),
37814304Swpaul			p, argp->map_parms.map,
37995658Sdes		      	NULL);
38012997Swpaul		} else {
38114304Swpaul			execl(ypxfr_command, "ypxfr",
38214304Swpaul			"-d", argp->map_parms.domain,
38324780Swpaul		      	"-h", mres->peer,
38414304Swpaul			"-C", t,
38514304Swpaul		      	g, inet_ntoa(rqhost->sin_addr),
38614304Swpaul			p, argp->map_parms.map,
38795658Sdes		      	NULL);
38812997Swpaul		}
38915426Swpaul		yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
39024780Swpaul		YPXFR_RETURN(YPXFR_XFRERR)
39146205Swpaul		/*
39246205Swpaul		 * Just to safe, prevent PR #10970 from biting us in
39346205Swpaul		 * the unlikely case that execing ypxfr fails. We don't
39446205Swpaul		 * want to have any child processes spawned from this
39546205Swpaul		 * child process.
39646205Swpaul		 */
39746205Swpaul		_exit(0);
39812997Swpaul		break;
39912891Swpaul	}
40012891Swpaul	case -1:
40112891Swpaul		yp_error("ypxfr fork(): %s", strerror(errno));
40224780Swpaul		YPXFR_RETURN(YPXFR_XFRERR)
40312891Swpaul		break;
40412891Swpaul	default:
40513375Swpaul		result.xfrstat = YPXFR_SUCC;
40612997Swpaul		children++;
40712891Swpaul		break;
40812891Swpaul	}
40913375Swpaul
41013375Swpaul	return (&result);
41112891Swpaul}
41215426Swpaul#undef YPXFR_RETURN
41312891Swpaul
41412891Swpaulvoid *
41512891Swpaulypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
41612891Swpaul{
41712891Swpaul	static char * result;
41812891Swpaul	static char rval = 0;
41912891Swpaul
42019161Swpaul#ifdef DB_CACHE
42119161Swpaul	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
42219161Swpaul#else
42312891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
42419161Swpaul#endif
42512891Swpaul		return (NULL);
42615426Swpaul#ifdef DB_CACHE
42715426Swpaul	/* clear out the database cache */
42815426Swpaul	yp_flush_all();
42915426Swpaul#endif
43014240Swpaul	/* Re-read the securenets database for the hell of it. */
43114240Swpaul	load_securenets();
43214240Swpaul
43312891Swpaul	result = &rval;
43412891Swpaul	return((void *) &result);
43512891Swpaul}
43612891Swpaul
43712891Swpaul/*
43812891Swpaul * For ypproc_all, we have to send a stream of ypresp_all structures
43912891Swpaul * via TCP, but the XDR filter generated from the yp.x protocol
44012891Swpaul * definition file only serializes one such structure. This means that
44112891Swpaul * to send the whole stream, you need a wrapper which feeds all the
44212891Swpaul * records into the underlying XDR routine until it hits an 'EOF.'
44312891Swpaul * But to use the wrapper, you have to violate the boundaries between
44412891Swpaul * RPC layers by calling svc_sendreply() directly from the ypproc_all
44512891Swpaul * service routine instead of letting the RPC dispatcher do it.
44612891Swpaul *
44712891Swpaul * Bleah.
44812891Swpaul */
44912891Swpaul
45012891Swpaul/*
45120100Swpaul * Custom XDR routine for serialzing results of ypproc_all: keep
45220100Swpaul * reading from the database and spew until we run out of records
45320100Swpaul * or encounter an error.
45412891Swpaul */
45512891Swpaulstatic bool_t
45612891Swpaulxdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
45712891Swpaul{
45820100Swpaul	while (1) {
45920100Swpaul		/* Get a record. */
46020100Swpaul		if ((objp->ypresp_all_u.val.stat =
46120818Swpaul			yp_nextbykey(&objp->ypresp_all_u.val.key,
46220818Swpaul				     &objp->ypresp_all_u.val.val)) == YP_TRUE) {
46320100Swpaul			objp->more = TRUE;
46420100Swpaul		} else {
46520100Swpaul			objp->more = FALSE;
46620100Swpaul		}
46720100Swpaul
46820100Swpaul		/* Serialize. */
46920100Swpaul		if (!xdr_ypresp_all(xdrs, objp))
47020100Swpaul			return(FALSE);
47120100Swpaul		if (objp->more == FALSE)
47220100Swpaul			return(TRUE);
47320100Swpaul	}
47412891Swpaul}
47512891Swpaul
47612891Swpaulypresp_all *
47712891Swpaulypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
47812891Swpaul{
47912891Swpaul	static ypresp_all  result;
48012891Swpaul
48112891Swpaul	/*
48212891Swpaul	 * Set this here so that the client will be forced to make
48312891Swpaul	 * at least one attempt to read from us even if all we're
48412891Swpaul	 * doing is returning an error.
48512891Swpaul	 */
48612891Swpaul	result.more = TRUE;
48714304Swpaul	result.ypresp_all_u.val.key.keydat_len = 0;
48814304Swpaul	result.ypresp_all_u.val.key.keydat_val = "";
48912891Swpaul
49019161Swpaul#ifdef DB_CACHE
49119161Swpaul	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
49219161Swpaul#else
49312891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
49419161Swpaul#endif
49512891Swpaul		result.ypresp_all_u.val.stat = YP_YPERR;
49612891Swpaul		return (&result);
49712891Swpaul	}
49812891Swpaul
49912891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
50012891Swpaul		result.ypresp_all_u.val.stat = YP_BADARGS;
50112891Swpaul		return (&result);
50212891Swpaul	}
50312891Swpaul
50420100Swpaul	/*
50521389Swpaul	 * XXX If we hit the child limit, fail the request.
50621389Swpaul	 * If we don't, and the map is large, we could block for
50721389Swpaul	 * a long time in the parent.
50821389Swpaul	 */
50921389Swpaul	if (children >= MAX_CHILDREN) {
51021389Swpaul		result.ypresp_all_u.val.stat = YP_YPERR;
51121389Swpaul		return(&result);
51221389Swpaul	}
51321389Swpaul
51421389Swpaul	/*
51520100Swpaul	 * The ypproc_all procedure can take a while to complete.
51620100Swpaul	 * Best to handle it in a subprocess so the parent doesn't
51720100Swpaul	 * block. (Is there a better way to do this? Maybe with
51820100Swpaul	 * async socket I/O?)
51920100Swpaul	 */
52043847Swpaul	if (!debug) {
52190297Sdes		switch (yp_fork()) {
52243847Swpaul		case 0:
52343847Swpaul			break;
52443847Swpaul		case -1:
52543847Swpaul			yp_error("ypall fork(): %s", strerror(errno));
52643847Swpaul			result.ypresp_all_u.val.stat = YP_YPERR;
52743847Swpaul			return(&result);
52843847Swpaul			break;
52943847Swpaul		default:
53043847Swpaul			children++;
53143847Swpaul			return (NULL);
53243847Swpaul			break;
53343847Swpaul		}
53420100Swpaul	}
53520100Swpaul
53646207Swpaul	/*
53746207Swpaul	 * Fix for PR #10971: don't let the child ypserv share
53846207Swpaul	 * DB handles with the parent process.
53946207Swpaul	 */
54046207Swpaul#ifdef DB_CACHE
54146207Swpaul	yp_flush_all();
54246207Swpaul#endif
54346207Swpaul
54420818Swpaul	if (yp_select_map(argp->map, argp->domain,
54520818Swpaul				&result.ypresp_all_u.val.key, 0) != YP_TRUE) {
54612891Swpaul		result.ypresp_all_u.val.stat = yp_errno;
54712891Swpaul		return(&result);
54812891Swpaul	}
54912891Swpaul
55012891Swpaul	/* Kick off the actual data transfer. */
55195658Sdes	svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_my_ypresp_all, &result);
55220100Swpaul
55312891Swpaul	/*
55446205Swpaul	 * Proper fix for PR #10970: exit here so that we don't risk
55546205Swpaul	 * having a child spawned from this sub-process.
55612891Swpaul	 */
55746205Swpaul	_exit(0);
55812891Swpaul}
55912891Swpaul
56012891Swpaulypresp_master *
56112891Swpaulypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
56212891Swpaul{
56312891Swpaul	static ypresp_master  result;
56415426Swpaul	static char ypvalbuf[YPMAXRECORD];
56528042Swpaul	keydat key = { MASTER_SZ, MASTER_STRING };
56620818Swpaul	valdat val;
56712891Swpaul
56814303Swpaul	result.peer = "";
56914303Swpaul
57019161Swpaul#ifdef DB_CACHE
57119161Swpaul	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
57219161Swpaul#else
57319161Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
57419161Swpaul#endif
57512891Swpaul		result.stat = YP_YPERR;
57612891Swpaul		return(&result);
57712891Swpaul	}
57812891Swpaul
57912891Swpaul	if (argp->domain == NULL) {
58012891Swpaul		result.stat = YP_BADARGS;
58112891Swpaul		return (&result);
58212891Swpaul	}
58312891Swpaul
58420818Swpaul	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
58520818Swpaul		result.stat = yp_errno;
58620818Swpaul		return(&result);
58720818Swpaul	}
58820818Swpaul
58915426Swpaul	/*
59015426Swpaul	 * Note that we copy the data retrieved from the database to
59115426Swpaul	 * a private buffer and NUL terminate the buffer rather than
59215426Swpaul	 * terminating the data in place. We do this because by stuffing
59315426Swpaul	 * a '\0' into data.data, we will actually be corrupting memory
59415426Swpaul	 * allocated by the DB package. This is a bad thing now that we
59515426Swpaul	 * cache DB handles rather than closing the database immediately.
59615426Swpaul	 */
59720818Swpaul	result.stat = yp_getbykey(&key, &val);
59820818Swpaul	if (result.stat == YP_TRUE) {
59995658Sdes		bcopy(val.valdat_val, &ypvalbuf, val.valdat_len);
60020818Swpaul		ypvalbuf[val.valdat_len] = '\0';
60195658Sdes		result.peer = ypvalbuf;
60212891Swpaul	} else
60312891Swpaul		result.peer = "";
60412891Swpaul
60512891Swpaul	return (&result);
60612891Swpaul}
60712891Swpaul
60812891Swpaulypresp_order *
60912891Swpaulypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
61012891Swpaul{
61112891Swpaul	static ypresp_order  result;
61228042Swpaul	keydat key = { ORDER_SZ, ORDER_STRING };
61320818Swpaul	valdat val;
61412891Swpaul
61514304Swpaul	result.ordernum = 0;
61614304Swpaul
61719161Swpaul#ifdef DB_CACHE
61819161Swpaul	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
61919161Swpaul#else
62019161Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
62119161Swpaul#endif
62212891Swpaul		result.stat = YP_YPERR;
62312891Swpaul		return(&result);
62412891Swpaul	}
62512891Swpaul
62612891Swpaul	if (argp->domain == NULL) {
62712891Swpaul		result.stat = YP_BADARGS;
62812891Swpaul		return (&result);
62912891Swpaul	}
63090297Sdes
63112891Swpaul	/*
63212891Swpaul	 * We could just check the timestamp on the map file,
63312891Swpaul	 * but that's a hack: we'll only know the last time the file
63412891Swpaul	 * was touched, not the last time the database contents were
63512891Swpaul	 * updated.
63612891Swpaul	 */
63712891Swpaul
63820818Swpaul	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
63920818Swpaul		result.stat = yp_errno;
64020818Swpaul		return(&result);
64120818Swpaul	}
64220818Swpaul
64320818Swpaul	result.stat = yp_getbykey(&key, &val);
64420818Swpaul
64520818Swpaul	if (result.stat == YP_TRUE)
64695658Sdes		result.ordernum = atoi(val.valdat_val);
64712891Swpaul	else
64812891Swpaul		result.ordernum = 0;
64912891Swpaul
65012891Swpaul	return (&result);
65112891Swpaul}
65212891Swpaul
65390298Sdesstatic void yp_maplist_free(struct ypmaplist *yp_maplist)
65412891Swpaul{
65512891Swpaul	register struct ypmaplist *next;
65612891Swpaul
65790297Sdes	while (yp_maplist) {
65812891Swpaul		next = yp_maplist->next;
65912891Swpaul		free(yp_maplist->map);
66012891Swpaul		free(yp_maplist);
66112891Swpaul		yp_maplist = next;
66212891Swpaul	}
66312891Swpaul	return;
66412891Swpaul}
66512891Swpaul
66690298Sdesstatic struct ypmaplist *
66790298Sdesyp_maplist_create(const char *domain)
66812891Swpaul{
66912891Swpaul	char yp_mapdir[MAXPATHLEN + 2];
67012891Swpaul	char yp_mapname[MAXPATHLEN + 2];
67112891Swpaul	struct ypmaplist *cur = NULL;
67212891Swpaul	struct ypmaplist *yp_maplist = NULL;
67312891Swpaul	DIR *dird;
67412891Swpaul	struct dirent *dirp;
67512891Swpaul	struct stat statbuf;
67612891Swpaul
67712891Swpaul	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
67812891Swpaul
67912891Swpaul	if ((dird = opendir(yp_mapdir)) == NULL) {
68013800Swpaul		yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno));
68112891Swpaul		return(NULL);
68212891Swpaul	}
68312891Swpaul
68412891Swpaul	while ((dirp = readdir(dird)) != NULL) {
68512891Swpaul		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
68614304Swpaul			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",
68714304Swpaul							yp_mapdir,dirp->d_name);
68814304Swpaul			if (stat(yp_mapname, &statbuf) < 0 ||
68914304Swpaul						!S_ISREG(statbuf.st_mode))
69012891Swpaul				continue;
69114304Swpaul			if ((cur = (struct ypmaplist *)
69216044Swpaul				malloc(sizeof(struct ypmaplist))) == NULL) {
69330827Scharnier				yp_error("malloc() failed");
69412891Swpaul				closedir(dird);
69512891Swpaul				yp_maplist_free(yp_maplist);
69612891Swpaul				return(NULL);
69712891Swpaul			}
69895658Sdes			if ((cur->map = strdup(dirp->d_name)) == NULL) {
69914304Swpaul				yp_error("strdup() failed: %s",strerror(errno));
70012891Swpaul				closedir(dird);
70112891Swpaul				yp_maplist_free(yp_maplist);
70212891Swpaul				return(NULL);
70312891Swpaul			}
70412891Swpaul			cur->next = yp_maplist;
70512891Swpaul			yp_maplist = cur;
70612891Swpaul			if (debug)
70712891Swpaul				yp_error("map: %s", yp_maplist->map);
70812891Swpaul		}
70912891Swpaul
71012891Swpaul	}
71112891Swpaul	closedir(dird);
71212891Swpaul	return(yp_maplist);
71312891Swpaul}
71412891Swpaul
71512891Swpaulypresp_maplist *
71612891Swpaulypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
71712891Swpaul{
71815426Swpaul	static ypresp_maplist  result = { 0, NULL };
71912891Swpaul
72019161Swpaul#ifdef DB_CACHE
72119161Swpaul	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
72219161Swpaul#else
72312891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
72419161Swpaul#endif
72512891Swpaul		result.stat = YP_YPERR;
72612891Swpaul		return(&result);
72712891Swpaul	}
72812891Swpaul
72912891Swpaul	if (argp == NULL) {
73012891Swpaul		result.stat = YP_BADARGS;
73112891Swpaul		return (&result);
73212891Swpaul	}
73390297Sdes
73412891Swpaul	if (yp_validdomain(*argp)) {
73512891Swpaul		result.stat = YP_NODOM;
73612891Swpaul		return (&result);
73712891Swpaul	}
73812891Swpaul
73912891Swpaul	/*
74012891Swpaul	 * We have to construct a linked list for the ypproc_maplist
74112891Swpaul	 * procedure using dynamically allocated memory. Since the XDR
74212891Swpaul	 * layer won't free this list for us, we have to deal with it
74312891Swpaul	 * ourselves. We call yp_maplist_free() first to free any
74412891Swpaul	 * previously allocated data we may have accumulated to insure
74512891Swpaul	 * that we have only one linked list in memory at any given
74612891Swpaul	 * time.
74712891Swpaul	 */
74812891Swpaul
74912891Swpaul	yp_maplist_free(result.maps);
75012891Swpaul
75112891Swpaul	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
75212891Swpaul		yp_error("yp_maplist_create failed");
75312891Swpaul		result.stat = YP_YPERR;
75412891Swpaul		return(&result);
75512891Swpaul	} else
75612891Swpaul		result.stat = YP_TRUE;
75712891Swpaul
75812891Swpaul	return (&result);
75912891Swpaul}
76014262Swpaul
76114262Swpaul/*
76214262Swpaul * NIS v1 support. The nullproc, domain and domain_nonack
76314262Swpaul * functions from v1 are identical to those in v2, so all
76414262Swpaul * we have to do is hand off to them.
76514262Swpaul *
76614262Swpaul * The other functions are mostly just wrappers around their v2
76714262Swpaul * counterparts. For example, for the v1 'match' procedure, we
76814262Swpaul * crack open the argument structure, make a request to the v2
76914262Swpaul * 'match' function, repackage the data into a v1 response and
77014262Swpaul * then send it on its way.
77114262Swpaul *
77214262Swpaul * Note that we don't support the pull, push and get procedures.
77314262Swpaul * There's little documentation available to show what they
77414262Swpaul * do, and I suspect they're meant largely for map transfers
77514262Swpaul * between master and slave servers.
77614262Swpaul */
77714262Swpaul
77814262Swpaulvoid *
77914262Swpaulypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
78014262Swpaul{
78114262Swpaul	return(ypproc_null_2_svc(argp, rqstp));
78214262Swpaul}
78314262Swpaul
78414262Swpaulbool_t *
78514262Swpaulypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
78614262Swpaul{
78714262Swpaul	return(ypproc_domain_2_svc(argp, rqstp));
78814262Swpaul}
78914262Swpaul
79014262Swpaulbool_t *
79114262Swpaulypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
79214262Swpaul{
79314262Swpaul	return (ypproc_domain_nonack_2_svc(argp, rqstp));
79414262Swpaul}
79514262Swpaul
79614304Swpaul/*
79714304Swpaul * the 'match' procedure sends a response of type YPRESP_VAL
79814304Swpaul */
79914262Swpaulypresponse *
80014262Swpaulypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
80114262Swpaul{
80214262Swpaul	static ypresponse  result;
80314262Swpaul	ypresp_val *v2_result;
80414262Swpaul
80514262Swpaul	result.yp_resptype = YPRESP_VAL;
80614304Swpaul	result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
80714304Swpaul	result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
80814262Swpaul
80914262Swpaul	if (argp->yp_reqtype != YPREQ_KEY) {
81014262Swpaul		result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
81114262Swpaul		return(&result);
81214262Swpaul	}
81314262Swpaul
81414262Swpaul	v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
81514262Swpaul	if (v2_result == NULL)
81614262Swpaul		return(NULL);
81714262Swpaul
81895658Sdes	bcopy(v2_result, &result.ypresponse_u.yp_resp_valtype,
81914262Swpaul	      sizeof(ypresp_val));
82014262Swpaul
82114262Swpaul	return (&result);
82214262Swpaul}
82314262Swpaul
82414304Swpaul/*
82514304Swpaul * the 'first' procedure sends a response of type YPRESP_KEY_VAL
82614304Swpaul */
82714262Swpaulypresponse *
82814262Swpaulypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
82914262Swpaul{
83014262Swpaul	static ypresponse  result;
83114262Swpaul	ypresp_key_val *v2_result;
83214262Swpaul
83314262Swpaul	result.yp_resptype = YPRESP_KEY_VAL;
83414304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
83514304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
83614304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
83714304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
83814262Swpaul
83914262Swpaul	if (argp->yp_reqtype != YPREQ_NOKEY) {
84014262Swpaul		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
84114262Swpaul		return(&result);
84214262Swpaul	}
84314262Swpaul
84414262Swpaul	v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
84514262Swpaul									rqstp);
84614262Swpaul	if (v2_result == NULL)
84714262Swpaul		return(NULL);
84814262Swpaul
84995658Sdes	bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype,
85014262Swpaul	      sizeof(ypresp_key_val));
85114262Swpaul
85214262Swpaul	return (&result);
85314262Swpaul}
85414262Swpaul
85514304Swpaul/*
85614304Swpaul * the 'next' procedure sends a response of type YPRESP_KEY_VAL
85714304Swpaul */
85814262Swpaulypresponse *
85914262Swpaulypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
86014262Swpaul{
86114262Swpaul	static ypresponse  result;
86214262Swpaul	ypresp_key_val *v2_result;
86314262Swpaul
86414262Swpaul	result.yp_resptype = YPRESP_KEY_VAL;
86514304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
86614304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
86714304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
86814304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
86914262Swpaul
87014262Swpaul	if (argp->yp_reqtype != YPREQ_KEY) {
87114262Swpaul		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
87214262Swpaul		return(&result);
87314262Swpaul	}
87414262Swpaul
87514262Swpaul	v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
87614262Swpaul	if (v2_result == NULL)
87714262Swpaul		return(NULL);
87814262Swpaul
87995658Sdes	bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype,
88014262Swpaul	      sizeof(ypresp_key_val));
88114262Swpaul
88214262Swpaul	return (&result);
88314262Swpaul}
88414262Swpaul
88514304Swpaul/*
88614304Swpaul * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
88714304Swpaul */
88814262Swpaulypresponse *
88914262Swpaulypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
89014262Swpaul{
89114262Swpaul	static ypresponse  result;
89214262Swpaul	ypresp_master *v2_result1;
89314262Swpaul	ypresp_order *v2_result2;
89414262Swpaul
89514262Swpaul	result.yp_resptype = YPRESP_MAP_PARMS;
89614262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.domain =
89714262Swpaul		argp->yprequest_u.yp_req_nokeytype.domain;
89814262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.map =
89914262Swpaul		argp->yprequest_u.yp_req_nokeytype.map;
90014262Swpaul	/*
90114262Swpaul	 * Hmm... there is no 'status' value in the
90214262Swpaul	 * yp_resp_map_parmstype structure, so I have to
90314262Swpaul	 * guess at what to do to indicate a failure.
90414262Swpaul	 * I hope this is right.
90514262Swpaul	 */
90614262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
90714262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.peer = "";
90814262Swpaul
90914262Swpaul	if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
91014262Swpaul		return(&result);
91114262Swpaul	}
91214262Swpaul
91314262Swpaul	v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
91414262Swpaul									rqstp);
91514262Swpaul	if (v2_result1 == NULL)
91614262Swpaul		return(NULL);
91714262Swpaul
91814262Swpaul	if (v2_result1->stat != YP_TRUE) {
91914262Swpaul		return(&result);
92014262Swpaul	}
92114262Swpaul
92214262Swpaul	v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
92314262Swpaul									rqstp);
92414262Swpaul	if (v2_result2 == NULL)
92514262Swpaul		return(NULL);
92614262Swpaul
92714262Swpaul	if (v2_result2->stat != YP_TRUE) {
92814262Swpaul		return(&result);
92914262Swpaul	}
93014262Swpaul
93114262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.peer =
93214262Swpaul		v2_result1->peer;
93314262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.ordernum =
93414262Swpaul		v2_result2->ordernum;
93514262Swpaul
93614262Swpaul	return (&result);
93714262Swpaul}
93814262Swpaul
93914262Swpaulypresponse *
94014262Swpaulypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
94114262Swpaul{
94214262Swpaul	static ypresponse  result;
94314262Swpaul
94414262Swpaul	/*
94514262Swpaul	 * Not implemented.
94614262Swpaul	 */
94714262Swpaul
94814262Swpaul	return (&result);
94914262Swpaul}
95014262Swpaul
95114262Swpaulypresponse *
95214262Swpaulypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
95314262Swpaul{
95414262Swpaul	static ypresponse  result;
95514262Swpaul
95614262Swpaul	/*
95714262Swpaul	 * Not implemented.
95814262Swpaul	 */
95914262Swpaul
96014262Swpaul	return (&result);
96114262Swpaul}
96214262Swpaul
96314262Swpaulypresponse *
96414262Swpaulypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
96514262Swpaul{
96614262Swpaul	static ypresponse  result;
96714262Swpaul
96814262Swpaul	/*
96914262Swpaul	 * Not implemented.
97014262Swpaul	 */
97114262Swpaul
97214262Swpaul	return (&result);
97314262Swpaul}
974