yp_server.c revision 15426
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
3412891Swpaul#include "yp_extern.h"
3512891Swpaul#include "yp.h"
3612891Swpaul#include <stdlib.h>
3712891Swpaul#include <dirent.h>
3812891Swpaul#include <sys/stat.h>
3912891Swpaul#include <sys/param.h>
4012891Swpaul#include <errno.h>
4112891Swpaul#include <sys/types.h>
4212891Swpaul#include <sys/socket.h>
4312891Swpaul#include <netinet/in.h>
4412891Swpaul#include <arpa/inet.h>
4512997Swpaul#include <rpc/rpc.h>
4612891Swpaul
4712891Swpaul#ifndef lint
4815426Swpaulstatic char rcsid[] = "$Id: yp_server.c,v 1.5 1996/04/26 04:35:53 wpaul Exp wpaul $";
4912891Swpaul#endif /* not lint */
5012891Swpaul
5112891Swpaulint forked = 0;
5212891Swpaulint children = 0;
5312891SwpaulDB *spec_dbp = NULL;	/* Special global DB handle for ypproc_all. */
5415426Swpaulchar *master_string = "YP_MASTER_NAME";
5515426Swpaulchar *order_string = "YP_LAST_MODIFIED";
5612891Swpaul
5715426Swpaul#define YP_ALL_TIMEOUT 10
5815426Swpaul
5915426Swpaulstatic int yp_all_timed_out = 0;
6015426Swpaul
6114262Swpaul/*
6214262Swpaul * NIS v2 support. This is where most of the action happens.
6314262Swpaul */
6414262Swpaul
6512891Swpaulvoid *
6612891Swpaulypproc_null_2_svc(void *argp, struct svc_req *rqstp)
6712891Swpaul{
6812891Swpaul	static char * result;
6912891Swpaul	static char rval = 0;
7012891Swpaul
7112891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
7212891Swpaul		return(NULL);
7312891Swpaul
7412891Swpaul	result = &rval;
7512891Swpaul
7612891Swpaul	return((void *) &result);
7712891Swpaul}
7812891Swpaul
7912891Swpaulbool_t *
8012891Swpaulypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
8112891Swpaul{
8212891Swpaul	static bool_t  result;
8312891Swpaul
8412891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
8512891Swpaul		result = FALSE;
8612891Swpaul		return (&result);
8712891Swpaul	}
8812891Swpaul
8912891Swpaul	if (argp == NULL || yp_validdomain(*argp))
9012891Swpaul		result = FALSE;
9112891Swpaul	else
9212891Swpaul		result = TRUE;
9312891Swpaul
9412891Swpaul	return (&result);
9512891Swpaul}
9612891Swpaul
9712891Swpaulbool_t *
9812891Swpaulypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
9912891Swpaul{
10012891Swpaul	static bool_t  result;
10112891Swpaul
10212891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
10312891Swpaul		return (NULL);
10412891Swpaul
10512891Swpaul	if (argp == NULL || yp_validdomain(*argp))
10612891Swpaul		return (NULL);
10712891Swpaul	else
10812891Swpaul		result = TRUE;
10912891Swpaul
11012891Swpaul	return (&result);
11112891Swpaul}
11212891Swpaul
11312891Swpaulypresp_val *
11412891Swpaulypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
11512891Swpaul{
11612891Swpaul	static ypresp_val  result;
11712891Swpaul	DBT key, data;
11812891Swpaul
11914304Swpaul	result.val.valdat_val = "";
12014304Swpaul	result.val.valdat_len = 0;
12114304Swpaul
12212891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
12312891Swpaul		result.stat = YP_YPERR;
12412891Swpaul		return (&result);
12512891Swpaul	}
12612891Swpaul
12712891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
12812891Swpaul		result.stat = YP_BADARGS;
12912891Swpaul		return (&result);
13012891Swpaul	}
13112891Swpaul
13212891Swpaul	key.size = argp->key.keydat_len;
13312891Swpaul	key.data = argp->key.keydat_val;
13412891Swpaul
13515426Swpaul	if ((result.stat = yp_get_record(argp->domain, argp->map,
13615426Swpaul						&key, &data, 1)) == YP_TRUE) {
13712891Swpaul		result.val.valdat_len = data.size;
13812891Swpaul		result.val.valdat_val = data.data;
13912891Swpaul	}
14012891Swpaul
14112891Swpaul	/*
14212891Swpaul	 * Do DNS lookups for hosts maps if database lookup failed.
14312891Swpaul	 */
14412891Swpaul
14512891Swpaul	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
14612997Swpaul		char *rval = NULL;
14712891Swpaul
14812891Swpaul	/* DNS lookups can take time -- do them in a subprocess */
14912891Swpaul
15012891Swpaul		if (!debug && children < MAX_CHILDREN && fork()) {
15112891Swpaul			children++;
15212891Swpaul			forked = 0;
15312891Swpaul			/*
15412891Swpaul			 * Returning NULL here prevents svc_sendreply()
15512891Swpaul			 * from being called by the parent. This is vital
15612891Swpaul			 * since having both the parent and the child process
15712891Swpaul			 * call it would confuse the client.
15812891Swpaul			 */
15912891Swpaul			return (NULL);
16012891Swpaul		} else {
16112891Swpaul			forked++;
16212891Swpaul		}
16312891Swpaul
16412891Swpaul		if (debug)
16512891Swpaul			yp_error("Doing DNS lookup of %.*s",
16612891Swpaul			 	  argp->key.keydat_len,
16712891Swpaul				  argp->key.keydat_val);
16812891Swpaul
16912891Swpaul		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
17012891Swpaul		argp->key.keydat_val[argp->key.keydat_len] = '\0';
17112891Swpaul
17212891Swpaul		if (!strcmp(argp->map, "hosts.byname"))
17312891Swpaul			rval = yp_dnsname((char *)argp->key.keydat_val);
17412891Swpaul		else if (!strcmp(argp->map, "hosts.byaddr"))
17512891Swpaul			rval = yp_dnsaddr((const char *)argp->key.keydat_val);
17612891Swpaul
17712891Swpaul
17812891Swpaul		if (rval) {
17912891Swpaul			if (debug)
18014304Swpaul				yp_error("DNS lookup successful. Result: %s",
18114304Swpaul									rval);
18212891Swpaul			result.val.valdat_len = strlen(rval);
18312891Swpaul			result.val.valdat_val = rval;
18412891Swpaul			result.stat = YP_TRUE;
18512891Swpaul		} else {
18612891Swpaul			if (debug)
18712891Swpaul				yp_error("DNS lookup failed.");
18812891Swpaul			result.stat = YP_NOKEY;
18912891Swpaul		}
19012891Swpaul	}
19112891Swpaul
19212891Swpaul	return (&result);
19312891Swpaul}
19412891Swpaul
19512891Swpaulypresp_key_val *
19612891Swpaulypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
19712891Swpaul{
19812891Swpaul	static ypresp_key_val  result;
19912891Swpaul	DBT key, data;
20012891Swpaul	DB *dbp;
20112891Swpaul
20214304Swpaul	result.val.valdat_val = result.key.keydat_val = "";
20314304Swpaul	result.val.valdat_len = result.key.keydat_len = 0;
20414304Swpaul
20512891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
20612891Swpaul		result.stat = YP_YPERR;
20712891Swpaul		return (&result);
20812891Swpaul	}
20912891Swpaul
21012891Swpaul	if (argp->domain == NULL) {
21112891Swpaul		result.stat = YP_BADARGS;
21212891Swpaul		return (&result);
21312891Swpaul	}
21412891Swpaul
21515426Swpaul#ifdef DB_CACHE
21615426Swpaul	if ((dbp = yp_open_db_cache(argp->domain, argp->map, NULL, 0)) == NULL) {
21715426Swpaul#else
21812891Swpaul	if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
21915426Swpaul#endif
22012891Swpaul		result.stat = yp_errno;
22112891Swpaul		return(&result);
22212891Swpaul	}
22312891Swpaul
22412891Swpaul	key.data = NULL;
22512891Swpaul	key.size = 0;
22612891Swpaul
22715426Swpaul	if ((result.stat = yp_first_record(dbp, &key, &data, 0)) == YP_TRUE) {
22812891Swpaul		result.key.keydat_len = key.size;
22912891Swpaul		result.key.keydat_val = key.data;
23012891Swpaul		result.val.valdat_len = data.size;
23112891Swpaul		result.val.valdat_val = data.data;
23212891Swpaul	}
23315426Swpaul#ifndef DB_CACHE
23415426Swpaul	(void)(dbp->close)(dbp);
23515426Swpaul#endif
23612891Swpaul	return (&result);
23712891Swpaul}
23812891Swpaul
23912891Swpaulypresp_key_val *
24012891Swpaulypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
24112891Swpaul{
24212891Swpaul	static ypresp_key_val  result;
24312891Swpaul	DBT key, data;
24412891Swpaul	DB *dbp;
24512891Swpaul
24614304Swpaul	result.val.valdat_val = result.key.keydat_val = "";
24714304Swpaul	result.val.valdat_len = result.key.keydat_len = 0;
24815426Swpaul
24912891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
25012891Swpaul		result.stat = YP_YPERR;
25112891Swpaul		return (&result);
25212891Swpaul	}
25312891Swpaul
25412891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
25512891Swpaul		result.stat = YP_BADARGS;
25612891Swpaul		return (&result);
25712891Swpaul	}
25812891Swpaul
25915426Swpaul#ifdef DB_CACHE
26015426Swpaul	if ((dbp = yp_open_db_cache(argp->domain, argp->map,
26115426Swpaul					argp->key.keydat_val,
26215426Swpaul					argp->key.keydat_len)) == NULL) {
26315426Swpaul#else
26412891Swpaul	if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
26515426Swpaul#endif
26612891Swpaul		result.stat = yp_errno;
26712891Swpaul		return(&result);
26812891Swpaul	}
26912891Swpaul
27012891Swpaul	key.size = argp->key.keydat_len;
27112891Swpaul	key.data = argp->key.keydat_val;
27212891Swpaul
27315426Swpaul	if ((result.stat = yp_next_record(dbp, &key, &data,0,0)) == YP_TRUE) {
27412891Swpaul		result.key.keydat_len = key.size;
27512891Swpaul		result.key.keydat_val = key.data;
27612891Swpaul		result.val.valdat_len = data.size;
27712891Swpaul		result.val.valdat_val = data.data;
27812891Swpaul	}
27915426Swpaul#ifndef DB_CACHE
28015426Swpaul	(void)(dbp->close)(dbp);
28115426Swpaul#endif
28212891Swpaul	return (&result);
28312891Swpaul}
28412891Swpaul
28512997Swpaulstatic void ypxfr_callback(rval,addr,transid,prognum,port)
28612997Swpaul	ypxfrstat rval;
28712997Swpaul	struct sockaddr_in *addr;
28812997Swpaul	unsigned int transid;
28912997Swpaul	unsigned int prognum;
29012997Swpaul	unsigned long port;
29112997Swpaul{
29212997Swpaul	CLIENT *clnt;
29312997Swpaul	int sock = RPC_ANYSOCK;
29412997Swpaul	struct timeval timeout;
29512997Swpaul	yppushresp_xfr ypxfr_resp;
29613375Swpaul	struct rpc_err err;
29712997Swpaul
29813375Swpaul	timeout.tv_sec = 5;
29912997Swpaul	timeout.tv_usec = 0;
30012997Swpaul	addr->sin_port = htons(port);
30112997Swpaul
30212997Swpaul	if ((clnt = clntudp_create(addr, prognum, 1, timeout, &sock)) == NULL)
30312997Swpaul		yp_error("%s", clnt_spcreateerror("failed to establish \
30412997Swpaulcallback handle"));
30512997Swpaul
30612997Swpaul	ypxfr_resp.status = rval;
30712997Swpaul	ypxfr_resp.transid = transid;
30812997Swpaul
30913375Swpaul	/* Turn the timeout off -- we don't want to block. */
31013375Swpaul	timeout.tv_sec = 0;
31113375Swpaul	if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE)
31213375Swpaul		yp_error("failed to set timeout on ypproc_xfr callback");
31312997Swpaul
31413375Swpaul	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
31513375Swpaul		clnt_geterr(clnt, &err);
31613375Swpaul		if (err.re_status != RPC_SUCCESS &&
31713375Swpaul		    err.re_status != RPC_TIMEDOUT)
31813375Swpaul			yp_error("%s", clnt_sperror(clnt,
31913375Swpaul				"ypxfr callback failed"));
32013375Swpaul	}
32113375Swpaul
32212997Swpaul	clnt_destroy(clnt);
32312997Swpaul	return;
32412997Swpaul}
32512997Swpaul
32615426Swpaul#define YPXFR_RETURN(CODE) 						\
32715426Swpaul	/* Order is important: send regular RPC reply, then callback */	\
32815426Swpaul	result.xfrstat = CODE; 						\
32915426Swpaul	svc_sendreply(rqstp->rq_xprt, xdr_ypresp_xfr, (char *)&result); \
33015426Swpaul	ypxfr_callback(CODE,rqhost,argp->transid, 			\
33115426Swpaul					argp->prog,argp->port); 	\
33215426Swpaul	return(NULL);
33315426Swpaul
33412891Swpaulypresp_xfr *
33512891Swpaulypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
33612891Swpaul{
33712891Swpaul	static ypresp_xfr  result;
33812997Swpaul	struct sockaddr_in *rqhost;
33912891Swpaul
34013375Swpaul	result.transid = argp->transid;
34113375Swpaul	rqhost = svc_getcaller(rqstp->rq_xprt);
34213375Swpaul
34312891Swpaul	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
34415426Swpaul		YPXFR_RETURN(YPXFR_REFUSED);
34512891Swpaul	}
34612891Swpaul
34712891Swpaul	if (argp->map_parms.domain == NULL) {
34815426Swpaul		YPXFR_RETURN(YPXFR_BADARGS);
34912891Swpaul	}
35012891Swpaul
35112891Swpaul	if (yp_validdomain(argp->map_parms.domain)) {
35215426Swpaul		YPXFR_RETURN(YPXFR_NODOM);
35312891Swpaul	}
35412891Swpaul
35512891Swpaul	switch(fork()) {
35612891Swpaul	case 0:
35712891Swpaul	{
35812891Swpaul		char g[11], t[11], p[11];
35912891Swpaul		char ypxfr_command[MAXPATHLEN + 2];
36012891Swpaul
36112891Swpaul		sprintf (ypxfr_command, "%sypxfr", _PATH_LIBEXEC);
36212891Swpaul		sprintf (t, "%u", argp->transid);
36312891Swpaul		sprintf (g, "%u", argp->prog);
36412891Swpaul		sprintf (p, "%u", argp->port);
36512997Swpaul		if (debug)
36612997Swpaul			close(0); close(1); close(2);
36712997Swpaul		if (strcmp(yp_dir, _PATH_YP)) {
36814304Swpaul			execl(ypxfr_command, "ypxfr",
36914304Swpaul			"-d", argp->map_parms.domain,
37014304Swpaul		      	"-h", argp->map_parms.peer,
37114304Swpaul			"-p", yp_dir, "-C", t,
37214304Swpaul		      	g, inet_ntoa(rqhost->sin_addr),
37314304Swpaul			p, argp->map_parms.map,
37412997Swpaul		      	NULL);
37512997Swpaul		} else {
37614304Swpaul			execl(ypxfr_command, "ypxfr",
37714304Swpaul			"-d", argp->map_parms.domain,
37814304Swpaul		      	"-h", argp->map_parms.peer,
37914304Swpaul			"-C", t,
38014304Swpaul		      	g, inet_ntoa(rqhost->sin_addr),
38114304Swpaul			p, argp->map_parms.map,
38212997Swpaul		      	NULL);
38312997Swpaul		}
38412997Swpaul		forked++;
38515426Swpaul		yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
38615426Swpaul		YPXFR_RETURN(YPXFR_XFRERR);
38712997Swpaul		break;
38812891Swpaul	}
38912891Swpaul	case -1:
39012891Swpaul		yp_error("ypxfr fork(): %s", strerror(errno));
39115426Swpaul		YPXFR_RETURN(YPXFR_XFRERR);
39212891Swpaul		break;
39312891Swpaul	default:
39413375Swpaul		result.xfrstat = YPXFR_SUCC;
39512997Swpaul		children++;
39612997Swpaul		forked = 0;
39712891Swpaul		break;
39812891Swpaul	}
39913375Swpaul
40013375Swpaul	return (&result);
40112891Swpaul}
40215426Swpaul#undef YPXFR_RETURN
40312891Swpaul
40412891Swpaulvoid *
40512891Swpaulypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
40612891Swpaul{
40712891Swpaul	static char * result;
40812891Swpaul	static char rval = 0;
40912891Swpaul
41012891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
41112891Swpaul		return (NULL);
41215426Swpaul#ifdef DB_CACHE
41315426Swpaul	/* clear out the database cache */
41415426Swpaul	yp_flush_all();
41515426Swpaul#endif
41614240Swpaul	/* Re-read the securenets database for the hell of it. */
41714240Swpaul	load_securenets();
41814240Swpaul
41912891Swpaul	result = &rval;
42012891Swpaul	return((void *) &result);
42112891Swpaul}
42212891Swpaul
42312891Swpaul/*
42412891Swpaul * For ypproc_all, we have to send a stream of ypresp_all structures
42512891Swpaul * via TCP, but the XDR filter generated from the yp.x protocol
42612891Swpaul * definition file only serializes one such structure. This means that
42712891Swpaul * to send the whole stream, you need a wrapper which feeds all the
42812891Swpaul * records into the underlying XDR routine until it hits an 'EOF.'
42912891Swpaul * But to use the wrapper, you have to violate the boundaries between
43012891Swpaul * RPC layers by calling svc_sendreply() directly from the ypproc_all
43112891Swpaul * service routine instead of letting the RPC dispatcher do it.
43212891Swpaul *
43312891Swpaul * Bleah.
43412891Swpaul */
43512891Swpaul
43612891Swpaul/*
43712891Swpaul * Custom XDR routine for serialzing results of ypproc_all: keep
43812891Swpaul * reading from the database and spew until we run out of records
43912891Swpaul * or encounter an error.
44012891Swpaul */
44112891Swpaulstatic bool_t
44212891Swpaulxdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
44312891Swpaul{
44415426Swpaul	DBT key = { NULL, 0 } , data = { NULL, 0 };
44512891Swpaul
44612891Swpaul	while (1) {
44712891Swpaul		/* Get a record. */
44812891Swpaul		if ((objp->ypresp_all_u.val.stat =
44915426Swpaul	    		yp_next_record(spec_dbp,&key,&data,1,0)) == YP_TRUE) {
45012891Swpaul			objp->ypresp_all_u.val.val.valdat_len = data.size;
45112891Swpaul			objp->ypresp_all_u.val.val.valdat_val = data.data;
45212891Swpaul			objp->ypresp_all_u.val.key.keydat_len = key.size;
45312891Swpaul			objp->ypresp_all_u.val.key.keydat_val = key.data;
45412891Swpaul			objp->more = TRUE;
45512891Swpaul		} else {
45612891Swpaul			objp->more = FALSE;
45712891Swpaul		}
45812891Swpaul
45912891Swpaul		/* Serialize. */
46012891Swpaul		if (!xdr_ypresp_all(xdrs, objp))
46112891Swpaul			return(FALSE);
46212891Swpaul		if (objp->more == FALSE)
46312891Swpaul			return(TRUE);
46412891Swpaul	}
46512891Swpaul}
46612891Swpaul
46712891Swpaulypresp_all *
46812891Swpaulypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
46912891Swpaul{
47012891Swpaul	static ypresp_all  result;
47112891Swpaul
47212891Swpaul	/*
47312891Swpaul	 * Set this here so that the client will be forced to make
47412891Swpaul	 * at least one attempt to read from us even if all we're
47512891Swpaul	 * doing is returning an error.
47612891Swpaul	 */
47712891Swpaul	result.more = TRUE;
47814304Swpaul	result.ypresp_all_u.val.key.keydat_len = 0;
47914304Swpaul	result.ypresp_all_u.val.key.keydat_val = "";
48012891Swpaul
48112891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
48212891Swpaul		result.ypresp_all_u.val.stat = YP_YPERR;
48312891Swpaul		return (&result);
48412891Swpaul	}
48512891Swpaul
48612891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
48712891Swpaul		result.ypresp_all_u.val.stat = YP_BADARGS;
48812891Swpaul		return (&result);
48912891Swpaul	}
49012891Swpaul
49112891Swpaul	/*
49212891Swpaul	 * The ypproc_all procedure can take a while to complete.
49312891Swpaul	 * Best to handle it in a subprocess so the parent doesn't
49415426Swpaul	 * block. (Is there a better way to do this? Maybe with
49515426Swpaul	 * async socket I/O?)
49612891Swpaul	 */
49712891Swpaul	if (!debug && children < MAX_CHILDREN && fork()) {
49812891Swpaul		children++;
49912891Swpaul		forked = 0;
50012891Swpaul		return (NULL);
50112891Swpaul	} else {
50212891Swpaul		forked++;
50312891Swpaul	}
50412891Swpaul
50515426Swpaul#ifndef DB_CACHE
50612891Swpaul	if ((spec_dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
50712891Swpaul		result.ypresp_all_u.val.stat = yp_errno;
50812891Swpaul		return(&result);
50912891Swpaul	}
51015426Swpaul#else
51115426Swpaul	if ((spec_dbp = yp_open_db_cache(argp->domain, argp->map, NULL, 0)) == NULL) {
51215426Swpaul		result.ypresp_all_u.val.stat = yp_errno;
51315426Swpaul		return(&result);
51415426Swpaul	}
51515426Swpaul#endif
51612891Swpaul
51712891Swpaul	/* Kick off the actual data transfer. */
51812891Swpaul	svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result);
51912891Swpaul
52015426Swpaul#ifndef DB_CACHE
52112891Swpaul	(void)(spec_dbp->close)(spec_dbp);
52215426Swpaul#endif
52312891Swpaul	/*
52412891Swpaul	 * Returning NULL prevents the dispatcher from calling
52512891Swpaul	 * svc_sendreply() since we already did it.
52612891Swpaul	 */
52712891Swpaul	return (NULL);
52812891Swpaul}
52912891Swpaul
53012891Swpaulypresp_master *
53112891Swpaulypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
53212891Swpaul{
53312891Swpaul	static ypresp_master  result;
53415426Swpaul	static char ypvalbuf[YPMAXRECORD];
53515426Swpaul	DBT key, data;
53612891Swpaul
53714303Swpaul	result.peer = "";
53814303Swpaul
53912891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
54012891Swpaul		result.stat = YP_YPERR;
54112891Swpaul		return(&result);
54212891Swpaul	}
54312891Swpaul
54412891Swpaul	if (argp->domain == NULL) {
54512891Swpaul		result.stat = YP_BADARGS;
54612891Swpaul		return (&result);
54712891Swpaul	}
54812891Swpaul
54915426Swpaul	key.data = master_string;
55015426Swpaul	key.size = strlen(master_string);
55112891Swpaul
55215426Swpaul	/*
55315426Swpaul	 * Note that we copy the data retrieved from the database to
55415426Swpaul	 * a private buffer and NUL terminate the buffer rather than
55515426Swpaul	 * terminating the data in place. We do this because by stuffing
55615426Swpaul	 * a '\0' into data.data, we will actually be corrupting memory
55715426Swpaul	 * allocated by the DB package. This is a bad thing now that we
55815426Swpaul	 * cache DB handles rather than closing the database immediately.
55915426Swpaul	 */
56015426Swpaul	if ((result.stat = yp_get_record(argp->domain, argp->map,
56115426Swpaul						&key, &data, 1)) == YP_TRUE) {
56215426Swpaul		bcopy((char *)data.data, (char *)&ypvalbuf, data.size);
56315426Swpaul		ypvalbuf[data.size] = '\0';
56415426Swpaul		result.peer = (char *)&ypvalbuf;
56512891Swpaul	} else
56612891Swpaul		result.peer = "";
56712891Swpaul
56812891Swpaul	return (&result);
56912891Swpaul}
57012891Swpaul
57112891Swpaulypresp_order *
57212891Swpaulypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
57312891Swpaul{
57412891Swpaul	static ypresp_order  result;
57512891Swpaul	DBT key,data;
57612891Swpaul
57714304Swpaul	result.ordernum = 0;
57814304Swpaul
57912891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
58012891Swpaul		result.stat = YP_YPERR;
58112891Swpaul		return(&result);
58212891Swpaul	}
58312891Swpaul
58412891Swpaul	if (argp->domain == NULL) {
58512891Swpaul		result.stat = YP_BADARGS;
58612891Swpaul		return (&result);
58712891Swpaul	}
58812891Swpaul
58912891Swpaul	/*
59012891Swpaul	 * We could just check the timestamp on the map file,
59112891Swpaul	 * but that's a hack: we'll only know the last time the file
59212891Swpaul	 * was touched, not the last time the database contents were
59312891Swpaul	 * updated.
59412891Swpaul	 */
59512891Swpaul
59615426Swpaul	key.data = order_string;
59715426Swpaul	key.size = strlen(order_string);
59812891Swpaul
59915426Swpaul	if ((result.stat = yp_get_record(argp->domain, argp->map,
60015426Swpaul						&key, &data, 1)) == YP_TRUE)
60112891Swpaul		result.ordernum = atoi((char *)data.data);
60212891Swpaul	else
60312891Swpaul		result.ordernum = 0;
60412891Swpaul
60515426Swpaul
60612891Swpaul	return (&result);
60712891Swpaul}
60812891Swpaul
60912891Swpaulstatic void yp_maplist_free(yp_maplist)
61012891Swpaul	struct ypmaplist *yp_maplist;
61112891Swpaul{
61212891Swpaul	register struct ypmaplist *next;
61312891Swpaul
61412891Swpaul	while(yp_maplist) {
61512891Swpaul		next = yp_maplist->next;
61612891Swpaul		free(yp_maplist->map);
61712891Swpaul		free(yp_maplist);
61812891Swpaul		yp_maplist = next;
61912891Swpaul	}
62012891Swpaul	return;
62112891Swpaul}
62212891Swpaul
62312891Swpaulstatic struct ypmaplist *yp_maplist_create(domain)
62412891Swpaul	const char *domain;
62512891Swpaul{
62612891Swpaul	char yp_mapdir[MAXPATHLEN + 2];
62712891Swpaul	char yp_mapname[MAXPATHLEN + 2];
62812891Swpaul	struct ypmaplist *cur = NULL;
62912891Swpaul	struct ypmaplist *yp_maplist = NULL;
63012891Swpaul	DIR *dird;
63112891Swpaul	struct dirent *dirp;
63212891Swpaul	struct stat statbuf;
63312891Swpaul
63412891Swpaul	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
63512891Swpaul
63612891Swpaul	if ((dird = opendir(yp_mapdir)) == NULL) {
63713800Swpaul		yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno));
63812891Swpaul		return(NULL);
63912891Swpaul	}
64012891Swpaul
64112891Swpaul	while ((dirp = readdir(dird)) != NULL) {
64212891Swpaul		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
64314304Swpaul			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",
64414304Swpaul							yp_mapdir,dirp->d_name);
64514304Swpaul			if (stat(yp_mapname, &statbuf) < 0 ||
64614304Swpaul						!S_ISREG(statbuf.st_mode))
64712891Swpaul				continue;
64814304Swpaul			if ((cur = (struct ypmaplist *)
64914304Swpaul					malloc(sizeof(struct ypmaplist))) < 0) {
65014304Swpaul				yp_error("malloc() failed: %s",strerror(errno));
65112891Swpaul				closedir(dird);
65212891Swpaul				yp_maplist_free(yp_maplist);
65312891Swpaul				return(NULL);
65412891Swpaul			}
65512891Swpaul			if ((cur->map = (char *)strdup(dirp->d_name)) == NULL) {
65614304Swpaul				yp_error("strdup() failed: %s",strerror(errno));
65712891Swpaul				closedir(dird);
65812891Swpaul				yp_maplist_free(yp_maplist);
65912891Swpaul				return(NULL);
66012891Swpaul			}
66112891Swpaul			cur->next = yp_maplist;
66212891Swpaul			yp_maplist = cur;
66312891Swpaul			if (debug)
66412891Swpaul				yp_error("map: %s", yp_maplist->map);
66512891Swpaul		}
66612891Swpaul
66712891Swpaul	}
66812891Swpaul	closedir(dird);
66912891Swpaul	return(yp_maplist);
67012891Swpaul}
67112891Swpaul
67212891Swpaulypresp_maplist *
67312891Swpaulypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
67412891Swpaul{
67515426Swpaul	static ypresp_maplist  result = { 0, NULL };
67612891Swpaul
67712891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
67812891Swpaul		result.stat = YP_YPERR;
67912891Swpaul		return(&result);
68012891Swpaul	}
68112891Swpaul
68212891Swpaul	if (argp == NULL) {
68312891Swpaul		result.stat = YP_BADARGS;
68412891Swpaul		return (&result);
68512891Swpaul	}
68612891Swpaul
68712891Swpaul	if (yp_validdomain(*argp)) {
68812891Swpaul		result.stat = YP_NODOM;
68912891Swpaul		return (&result);
69012891Swpaul	}
69112891Swpaul
69212891Swpaul	/*
69312891Swpaul	 * We have to construct a linked list for the ypproc_maplist
69412891Swpaul	 * procedure using dynamically allocated memory. Since the XDR
69512891Swpaul	 * layer won't free this list for us, we have to deal with it
69612891Swpaul	 * ourselves. We call yp_maplist_free() first to free any
69712891Swpaul	 * previously allocated data we may have accumulated to insure
69812891Swpaul	 * that we have only one linked list in memory at any given
69912891Swpaul	 * time.
70012891Swpaul	 */
70112891Swpaul
70212891Swpaul	yp_maplist_free(result.maps);
70312891Swpaul
70412891Swpaul	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
70512891Swpaul		yp_error("yp_maplist_create failed");
70612891Swpaul		result.stat = YP_YPERR;
70712891Swpaul		return(&result);
70812891Swpaul	} else
70912891Swpaul		result.stat = YP_TRUE;
71012891Swpaul
71112891Swpaul	return (&result);
71212891Swpaul}
71314262Swpaul
71414262Swpaul/*
71514262Swpaul * NIS v1 support. The nullproc, domain and domain_nonack
71614262Swpaul * functions from v1 are identical to those in v2, so all
71714262Swpaul * we have to do is hand off to them.
71814262Swpaul *
71914262Swpaul * The other functions are mostly just wrappers around their v2
72014262Swpaul * counterparts. For example, for the v1 'match' procedure, we
72114262Swpaul * crack open the argument structure, make a request to the v2
72214262Swpaul * 'match' function, repackage the data into a v1 response and
72314262Swpaul * then send it on its way.
72414262Swpaul *
72514262Swpaul * Note that we don't support the pull, push and get procedures.
72614262Swpaul * There's little documentation available to show what they
72714262Swpaul * do, and I suspect they're meant largely for map transfers
72814262Swpaul * between master and slave servers.
72914262Swpaul */
73014262Swpaul
73114262Swpaulvoid *
73214262Swpaulypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
73314262Swpaul{
73414262Swpaul	return(ypproc_null_2_svc(argp, rqstp));
73514262Swpaul}
73614262Swpaul
73714262Swpaulbool_t *
73814262Swpaulypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
73914262Swpaul{
74014262Swpaul	return(ypproc_domain_2_svc(argp, rqstp));
74114262Swpaul}
74214262Swpaul
74314262Swpaulbool_t *
74414262Swpaulypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
74514262Swpaul{
74614262Swpaul	return (ypproc_domain_nonack_2_svc(argp, rqstp));
74714262Swpaul}
74814262Swpaul
74914304Swpaul/*
75014304Swpaul * the 'match' procedure sends a response of type YPRESP_VAL
75114304Swpaul */
75214262Swpaulypresponse *
75314262Swpaulypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
75414262Swpaul{
75514262Swpaul	static ypresponse  result;
75614262Swpaul	ypresp_val *v2_result;
75714262Swpaul
75814262Swpaul	result.yp_resptype = YPRESP_VAL;
75914304Swpaul	result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
76014304Swpaul	result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
76114262Swpaul
76214262Swpaul	if (argp->yp_reqtype != YPREQ_KEY) {
76314262Swpaul		result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
76414262Swpaul		return(&result);
76514262Swpaul	}
76614262Swpaul
76714262Swpaul	v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
76814262Swpaul	if (v2_result == NULL)
76914262Swpaul		return(NULL);
77014262Swpaul
77114262Swpaul	bcopy((char *)v2_result,
77214262Swpaul	      (char *)&result.ypresponse_u.yp_resp_valtype,
77314262Swpaul	      sizeof(ypresp_val));
77414262Swpaul
77514262Swpaul	return (&result);
77614262Swpaul}
77714262Swpaul
77814304Swpaul/*
77914304Swpaul * the 'first' procedure sends a response of type YPRESP_KEY_VAL
78014304Swpaul */
78114262Swpaulypresponse *
78214262Swpaulypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
78314262Swpaul{
78414262Swpaul	static ypresponse  result;
78514262Swpaul	ypresp_key_val *v2_result;
78614262Swpaul
78714262Swpaul	result.yp_resptype = YPRESP_KEY_VAL;
78814304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
78914304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
79014304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
79114304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
79214262Swpaul
79314262Swpaul	if (argp->yp_reqtype != YPREQ_NOKEY) {
79414262Swpaul		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
79514262Swpaul		return(&result);
79614262Swpaul	}
79714262Swpaul
79814262Swpaul	v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
79914262Swpaul									rqstp);
80014262Swpaul	if (v2_result == NULL)
80114262Swpaul		return(NULL);
80214262Swpaul
80314262Swpaul	bcopy((char *)v2_result,
80414262Swpaul	      (char *)&result.ypresponse_u.yp_resp_key_valtype,
80514262Swpaul	      sizeof(ypresp_key_val));
80614262Swpaul
80714262Swpaul	return (&result);
80814262Swpaul}
80914262Swpaul
81014304Swpaul/*
81114304Swpaul * the 'next' procedure sends a response of type YPRESP_KEY_VAL
81214304Swpaul */
81314262Swpaulypresponse *
81414262Swpaulypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
81514262Swpaul{
81614262Swpaul	static ypresponse  result;
81714262Swpaul	ypresp_key_val *v2_result;
81814262Swpaul
81914262Swpaul	result.yp_resptype = YPRESP_KEY_VAL;
82014304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
82114304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
82214304Swpaul	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
82314304Swpaul	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
82414262Swpaul
82514262Swpaul	if (argp->yp_reqtype != YPREQ_KEY) {
82614262Swpaul		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
82714262Swpaul		return(&result);
82814262Swpaul	}
82914262Swpaul
83014262Swpaul	v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
83114262Swpaul	if (v2_result == NULL)
83214262Swpaul		return(NULL);
83314262Swpaul
83414262Swpaul	bcopy((char *)v2_result,
83514262Swpaul	      (char *)&result.ypresponse_u.yp_resp_key_valtype,
83614262Swpaul	      sizeof(ypresp_key_val));
83714262Swpaul
83814262Swpaul	return (&result);
83914262Swpaul}
84014262Swpaul
84114304Swpaul/*
84214304Swpaul * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
84314304Swpaul */
84414262Swpaulypresponse *
84514262Swpaulypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
84614262Swpaul{
84714262Swpaul	static ypresponse  result;
84814262Swpaul	ypresp_master *v2_result1;
84914262Swpaul	ypresp_order *v2_result2;
85014262Swpaul
85114262Swpaul	result.yp_resptype = YPRESP_MAP_PARMS;
85214262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.domain =
85314262Swpaul		argp->yprequest_u.yp_req_nokeytype.domain;
85414262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.map =
85514262Swpaul		argp->yprequest_u.yp_req_nokeytype.map;
85614262Swpaul	/*
85714262Swpaul	 * Hmm... there is no 'status' value in the
85814262Swpaul	 * yp_resp_map_parmstype structure, so I have to
85914262Swpaul	 * guess at what to do to indicate a failure.
86014262Swpaul	 * I hope this is right.
86114262Swpaul	 */
86214262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
86314262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.peer = "";
86414262Swpaul
86514262Swpaul	if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
86614262Swpaul		return(&result);
86714262Swpaul	}
86814262Swpaul
86914262Swpaul	v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
87014262Swpaul									rqstp);
87114262Swpaul	if (v2_result1 == NULL)
87214262Swpaul		return(NULL);
87314262Swpaul
87414262Swpaul	if (v2_result1->stat != YP_TRUE) {
87514262Swpaul		return(&result);
87614262Swpaul	}
87714262Swpaul
87814262Swpaul	v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
87914262Swpaul									rqstp);
88014262Swpaul	if (v2_result2 == NULL)
88114262Swpaul		return(NULL);
88214262Swpaul
88314262Swpaul	if (v2_result2->stat != YP_TRUE) {
88414262Swpaul		return(&result);
88514262Swpaul	}
88614262Swpaul
88714262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.peer =
88814262Swpaul		v2_result1->peer;
88914262Swpaul	result.ypresponse_u.yp_resp_map_parmstype.ordernum =
89014262Swpaul		v2_result2->ordernum;
89114262Swpaul
89214262Swpaul	return (&result);
89314262Swpaul}
89414262Swpaul
89514262Swpaulypresponse *
89614262Swpaulypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
89714262Swpaul{
89814262Swpaul	static ypresponse  result;
89914262Swpaul
90014262Swpaul	/*
90114262Swpaul	 * Not implemented.
90214262Swpaul	 */
90314262Swpaul
90414262Swpaul	return (&result);
90514262Swpaul}
90614262Swpaul
90714262Swpaulypresponse *
90814262Swpaulypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
90914262Swpaul{
91014262Swpaul	static ypresponse  result;
91114262Swpaul
91214262Swpaul	/*
91314262Swpaul	 * Not implemented.
91414262Swpaul	 */
91514262Swpaul
91614262Swpaul	return (&result);
91714262Swpaul}
91814262Swpaul
91914262Swpaulypresponse *
92014262Swpaulypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
92114262Swpaul{
92214262Swpaul	static ypresponse  result;
92314262Swpaul
92414262Swpaul	/*
92514262Swpaul	 * Not implemented.
92614262Swpaul	 */
92714262Swpaul
92814262Swpaul	return (&result);
92914262Swpaul}
930