yp_server.c revision 12997
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
4812997Swpaulstatic char rcsid[] = "$Id: yp_server.c,v 1.1.1.1 1995/12/16 20:54:17 wpaul Exp $";
4912891Swpaul#endif /* not lint */
5012891Swpaul
5112891Swpaulint forked = 0;
5212891Swpaulint children = 0;
5312891SwpaulDB *spec_dbp = NULL;	/* Special global DB handle for ypproc_all. */
5412891Swpaul
5512891Swpaulvoid *
5612891Swpaulypproc_null_2_svc(void *argp, struct svc_req *rqstp)
5712891Swpaul{
5812891Swpaul	static char * result;
5912891Swpaul	static char rval = 0;
6012891Swpaul
6112891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
6212891Swpaul		return(NULL);
6312891Swpaul
6412891Swpaul	result = &rval;
6512891Swpaul
6612891Swpaul	return((void *) &result);
6712891Swpaul}
6812891Swpaul
6912891Swpaulbool_t *
7012891Swpaulypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
7112891Swpaul{
7212891Swpaul	static bool_t  result;
7312891Swpaul
7412891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
7512891Swpaul		result = FALSE;
7612891Swpaul		return (&result);
7712891Swpaul	}
7812891Swpaul
7912891Swpaul	if (argp == NULL || yp_validdomain(*argp))
8012891Swpaul		result = FALSE;
8112891Swpaul	else
8212891Swpaul		result = TRUE;
8312891Swpaul
8412891Swpaul	return (&result);
8512891Swpaul}
8612891Swpaul
8712891Swpaulbool_t *
8812891Swpaulypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
8912891Swpaul{
9012891Swpaul	static bool_t  result;
9112891Swpaul
9212891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
9312891Swpaul		return (NULL);
9412891Swpaul
9512891Swpaul	if (argp == NULL || yp_validdomain(*argp))
9612891Swpaul		return (NULL);
9712891Swpaul	else
9812891Swpaul		result = TRUE;
9912891Swpaul
10012891Swpaul	return (&result);
10112891Swpaul}
10212891Swpaul
10312891Swpaulypresp_val *
10412891Swpaulypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
10512891Swpaul{
10612891Swpaul	static ypresp_val  result;
10712891Swpaul	DBT key, data;
10812891Swpaul
10912891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
11012891Swpaul		result.stat = YP_YPERR;
11112891Swpaul		return (&result);
11212891Swpaul	}
11312891Swpaul
11412891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
11512891Swpaul		result.stat = YP_BADARGS;
11612891Swpaul		return (&result);
11712891Swpaul	}
11812891Swpaul
11912891Swpaul	if (yp_validdomain(argp->domain)) {
12012891Swpaul		result.stat = YP_NODOM;
12112891Swpaul		return(&result);
12212891Swpaul	}
12312891Swpaul
12412891Swpaul	key.size = argp->key.keydat_len;
12512891Swpaul	key.data = argp->key.keydat_val;
12612891Swpaul
12712891Swpaul	result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 0);
12812891Swpaul
12912891Swpaul	if (result.stat == YP_TRUE) {
13012891Swpaul		result.val.valdat_len = data.size;
13112891Swpaul		result.val.valdat_val = data.data;
13212891Swpaul	}
13312891Swpaul
13412891Swpaul	/*
13512891Swpaul	 * Do DNS lookups for hosts maps if database lookup failed.
13612891Swpaul	 */
13712891Swpaul
13812891Swpaul	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
13912997Swpaul		char *rval = NULL;
14012891Swpaul
14112891Swpaul	/* DNS lookups can take time -- do them in a subprocess */
14212891Swpaul
14312891Swpaul		if (!debug && children < MAX_CHILDREN && fork()) {
14412891Swpaul			children++;
14512891Swpaul			forked = 0;
14612891Swpaul			/*
14712891Swpaul			 * Returning NULL here prevents svc_sendreply()
14812891Swpaul			 * from being called by the parent. This is vital
14912891Swpaul			 * since having both the parent and the child process
15012891Swpaul			 * call it would confuse the client.
15112891Swpaul			 */
15212891Swpaul			return (NULL);
15312891Swpaul		} else {
15412891Swpaul			forked++;
15512891Swpaul		}
15612891Swpaul
15712891Swpaul		if (debug)
15812891Swpaul			yp_error("Doing DNS lookup of %.*s",
15912891Swpaul			 	  argp->key.keydat_len,
16012891Swpaul				  argp->key.keydat_val);
16112891Swpaul
16212891Swpaul		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
16312891Swpaul		argp->key.keydat_val[argp->key.keydat_len] = '\0';
16412891Swpaul
16512891Swpaul		if (!strcmp(argp->map, "hosts.byname"))
16612891Swpaul			rval = yp_dnsname((char *)argp->key.keydat_val);
16712891Swpaul		else if (!strcmp(argp->map, "hosts.byaddr"))
16812891Swpaul			rval = yp_dnsaddr((const char *)argp->key.keydat_val);
16912891Swpaul
17012891Swpaul
17112891Swpaul		if (rval) {
17212891Swpaul			if (debug)
17312891Swpaul				yp_error("DNS lookup successful. Result: %s", rval);
17412891Swpaul			result.val.valdat_len = strlen(rval);
17512891Swpaul			result.val.valdat_val = rval;
17612891Swpaul			result.stat = YP_TRUE;
17712891Swpaul		} else {
17812891Swpaul			if (debug)
17912891Swpaul				yp_error("DNS lookup failed.");
18012891Swpaul			result.stat = YP_NOKEY;
18112891Swpaul		}
18212891Swpaul	}
18312891Swpaul
18412891Swpaul	return (&result);
18512891Swpaul}
18612891Swpaul
18712891Swpaulypresp_key_val *
18812891Swpaulypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
18912891Swpaul{
19012891Swpaul	static ypresp_key_val  result;
19112891Swpaul	DBT key, data;
19212891Swpaul	DB *dbp;
19312891Swpaul
19412891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
19512891Swpaul		result.stat = YP_YPERR;
19612891Swpaul		return (&result);
19712891Swpaul	}
19812891Swpaul
19912891Swpaul	if (argp->domain == NULL) {
20012891Swpaul		result.stat = YP_BADARGS;
20112891Swpaul		return (&result);
20212891Swpaul	}
20312891Swpaul
20412891Swpaul	if (yp_validdomain(argp->domain)) {
20512891Swpaul		result.stat = YP_NODOM;
20612891Swpaul		return(&result);
20712891Swpaul	}
20812891Swpaul
20912891Swpaul	if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
21012891Swpaul		result.stat = yp_errno;
21112891Swpaul		return(&result);
21212891Swpaul	}
21312891Swpaul
21412891Swpaul	key.data = NULL;
21512891Swpaul	key.size = 0;
21612891Swpaul	result.stat = yp_first_record(dbp, &key, &data);
21712891Swpaul	(void)(dbp->close)(dbp);
21812891Swpaul
21912891Swpaul	if (result.stat == YP_TRUE) {
22012891Swpaul		result.key.keydat_len = key.size;
22112891Swpaul		result.key.keydat_val = key.data;
22212891Swpaul		result.val.valdat_len = data.size;
22312891Swpaul		result.val.valdat_val = data.data;
22412891Swpaul	}
22512891Swpaul
22612891Swpaul	return (&result);
22712891Swpaul}
22812891Swpaul
22912891Swpaulypresp_key_val *
23012891Swpaulypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
23112891Swpaul{
23212891Swpaul	static ypresp_key_val  result;
23312891Swpaul	DBT key, data;
23412891Swpaul	DB *dbp;
23512891Swpaul
23612891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
23712891Swpaul		result.stat = YP_YPERR;
23812891Swpaul		return (&result);
23912891Swpaul	}
24012891Swpaul
24112891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
24212891Swpaul		result.stat = YP_BADARGS;
24312891Swpaul		return (&result);
24412891Swpaul	}
24512891Swpaul
24612891Swpaul	if (yp_validdomain(argp->domain)) {
24712891Swpaul		result.stat = YP_NODOM;
24812891Swpaul		return(&result);
24912891Swpaul	}
25012891Swpaul
25112891Swpaul	if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
25212891Swpaul		result.stat = yp_errno;
25312891Swpaul		return(&result);
25412891Swpaul	}
25512891Swpaul
25612891Swpaul	key.size = argp->key.keydat_len;
25712891Swpaul	key.data = argp->key.keydat_val;
25812891Swpaul
25912891Swpaul	result.stat = yp_next_record(dbp, &key, &data, 0);
26012891Swpaul	(void)(dbp->close)(dbp);
26112891Swpaul
26212891Swpaul	if (result.stat == YP_TRUE) {
26312891Swpaul		result.key.keydat_len = key.size;
26412891Swpaul		result.key.keydat_val = key.data;
26512891Swpaul		result.val.valdat_len = data.size;
26612891Swpaul		result.val.valdat_val = data.data;
26712891Swpaul	}
26812891Swpaul
26912891Swpaul	return (&result);
27012891Swpaul}
27112891Swpaul
27212997Swpaulstatic void ypxfr_callback(rval,addr,transid,prognum,port)
27312997Swpaul	ypxfrstat rval;
27412997Swpaul	struct sockaddr_in *addr;
27512997Swpaul	unsigned int transid;
27612997Swpaul	unsigned int prognum;
27712997Swpaul	unsigned long port;
27812997Swpaul{
27912997Swpaul	CLIENT *clnt;
28012997Swpaul	int sock = RPC_ANYSOCK;
28112997Swpaul	struct timeval timeout;
28212997Swpaul	yppushresp_xfr ypxfr_resp;
28312997Swpaul
28412997Swpaul	timeout.tv_sec = 20;
28512997Swpaul	timeout.tv_usec = 0;
28612997Swpaul	addr->sin_port = htons(port);
28712997Swpaul
28812997Swpaul	if ((clnt = clntudp_create(addr, prognum, 1, timeout, &sock)) == NULL)
28912997Swpaul		yp_error("%s", clnt_spcreateerror("failed to establish \
29012997Swpaulcallback handle"));
29112997Swpaul
29212997Swpaul	ypxfr_resp.status = rval;
29312997Swpaul	ypxfr_resp.transid = transid;
29412997Swpaul
29512997Swpaul	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL)
29612997Swpaul		yp_error("%s", clnt_sperror(clnt, "ypxfr callback failed"));
29712997Swpaul
29812997Swpaul	clnt_destroy(clnt);
29912997Swpaul	return;
30012997Swpaul}
30112997Swpaul
30212891Swpaulypresp_xfr *
30312891Swpaulypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
30412891Swpaul{
30512891Swpaul	static ypresp_xfr  result;
30612997Swpaul	struct sockaddr_in *rqhost;
30712891Swpaul
30812891Swpaul	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
30912891Swpaul		result.xfrstat = YPXFR_REFUSED;
31012891Swpaul		return(&result);
31112891Swpaul	}
31212891Swpaul
31312891Swpaul	if (argp->map_parms.domain == NULL) {
31412891Swpaul		result.xfrstat = YPXFR_BADARGS;
31512891Swpaul		return (&result);
31612891Swpaul	}
31712891Swpaul
31812891Swpaul	if (yp_validdomain(argp->map_parms.domain)) {
31912891Swpaul		result.xfrstat = YPXFR_NODOM;
32012891Swpaul		return(&result);
32112891Swpaul	}
32212891Swpaul
32312997Swpaul	rqhost = svc_getcaller(rqstp->rq_xprt);
32412997Swpaul
32512891Swpaul	switch(fork()) {
32612891Swpaul	case 0:
32712891Swpaul	{
32812891Swpaul		char g[11], t[11], p[11];
32912891Swpaul		char ypxfr_command[MAXPATHLEN + 2];
33012891Swpaul
33112891Swpaul		sprintf (ypxfr_command, "%sypxfr", _PATH_LIBEXEC);
33212891Swpaul		sprintf (t, "%u", argp->transid);
33312891Swpaul		sprintf (g, "%u", argp->prog);
33412891Swpaul		sprintf (p, "%u", argp->port);
33512997Swpaul		if (debug)
33612997Swpaul			close(0); close(1); close(2);
33712997Swpaul		if (strcmp(yp_dir, _PATH_YP)) {
33812997Swpaul			execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain,
33912997Swpaul		      	"-h", argp->map_parms.peer, "-f", "-p", yp_dir, "-C", t,
34012997Swpaul		      	g, inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map,
34112997Swpaul		      	NULL);
34212997Swpaul		} else {
34312997Swpaul			execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain,
34412997Swpaul		      	"-h", argp->map_parms.peer, "-f", "-C", t, g,
34512997Swpaul		      	inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map,
34612997Swpaul		      	NULL);
34712997Swpaul		}
34812997Swpaul		forked++;
34912891Swpaul		yp_error("ypxfr execl(): %s", strerror(errno));
35012997Swpaul		ypxfr_callback(YPXFR_XFRERR,rqhost,argp->transid,
35112997Swpaul			       argp->prog,argp->port);
35212997Swpaul		result.xfrstat = YPXFR_XFRERR;
35312997Swpaul		return(&result);
35412997Swpaul		break;
35512891Swpaul	}
35612891Swpaul	case -1:
35712891Swpaul		yp_error("ypxfr fork(): %s", strerror(errno));
35812997Swpaul		ypxfr_callback(YPXFR_XFRERR,rqhost,argp->transid,
35912997Swpaul			       argp->prog,argp->port);
36012891Swpaul		result.xfrstat = YPXFR_XFRERR;
36112997Swpaul		return(&result);
36212891Swpaul		break;
36312891Swpaul	default:
36412997Swpaul		children++;
36512997Swpaul		forked = 0;
36612891Swpaul		break;
36712891Swpaul	}
36812997Swpaul	/* Don't return anything -- it's up to ypxfr to do that. */
36912997Swpaul	return (NULL);
37012891Swpaul}
37112891Swpaul
37212891Swpaulvoid *
37312891Swpaulypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
37412891Swpaul{
37512891Swpaul	static char * result;
37612891Swpaul	static char rval = 0;
37712891Swpaul
37812891Swpaul	/*
37912891Swpaul	 * We don't have to do anything for ypproc_clear. Unlike
38012891Swpaul	 * the SunOS ypserv, we don't hold out database descriptors
38112891Swpaul	 * open forever.
38212891Swpaul	 */
38312891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp))
38412891Swpaul		return (NULL);
38512891Swpaul
38612891Swpaul	result = &rval;
38712891Swpaul	return((void *) &result);
38812891Swpaul}
38912891Swpaul
39012891Swpaul/*
39112891Swpaul * For ypproc_all, we have to send a stream of ypresp_all structures
39212891Swpaul * via TCP, but the XDR filter generated from the yp.x protocol
39312891Swpaul * definition file only serializes one such structure. This means that
39412891Swpaul * to send the whole stream, you need a wrapper which feeds all the
39512891Swpaul * records into the underlying XDR routine until it hits an 'EOF.'
39612891Swpaul * But to use the wrapper, you have to violate the boundaries between
39712891Swpaul * RPC layers by calling svc_sendreply() directly from the ypproc_all
39812891Swpaul * service routine instead of letting the RPC dispatcher do it.
39912891Swpaul *
40012891Swpaul * Bleah.
40112891Swpaul */
40212891Swpaul
40312891Swpaul/*
40412891Swpaul * Custom XDR routine for serialzing results of ypproc_all: keep
40512891Swpaul * reading from the database and spew until we run out of records
40612891Swpaul * or encounter an error.
40712891Swpaul */
40812891Swpaulstatic bool_t
40912891Swpaulxdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
41012891Swpaul{
41112891Swpaul	DBT key, data;
41212891Swpaul
41312891Swpaul	while (1) {
41412891Swpaul		/* Get a record. */
41512891Swpaul		key.size = objp->ypresp_all_u.val.key.keydat_len;
41612891Swpaul		key.data = objp->ypresp_all_u.val.key.keydat_val;
41712891Swpaul
41812891Swpaul		if ((objp->ypresp_all_u.val.stat =
41912891Swpaul		    yp_next_record(spec_dbp,&key,&data,1)) == YP_TRUE) {
42012891Swpaul			objp->ypresp_all_u.val.val.valdat_len = data.size;
42112891Swpaul			objp->ypresp_all_u.val.val.valdat_val = data.data;
42212891Swpaul			objp->ypresp_all_u.val.key.keydat_len = key.size;
42312891Swpaul			objp->ypresp_all_u.val.key.keydat_val = key.data;
42412891Swpaul			objp->more = TRUE;
42512891Swpaul		} else {
42612891Swpaul			objp->more = FALSE;
42712891Swpaul		}
42812891Swpaul
42912891Swpaul		/* Serialize. */
43012891Swpaul		if (!xdr_ypresp_all(xdrs, objp))
43112891Swpaul			return(FALSE);
43212891Swpaul		if (objp->more == FALSE)
43312891Swpaul			return(TRUE);
43412891Swpaul	}
43512891Swpaul}
43612891Swpaul
43712891Swpaulypresp_all *
43812891Swpaulypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
43912891Swpaul{
44012891Swpaul	static ypresp_all  result;
44112891Swpaul
44212891Swpaul	/*
44312891Swpaul	 * Set this here so that the client will be forced to make
44412891Swpaul	 * at least one attempt to read from us even if all we're
44512891Swpaul	 * doing is returning an error.
44612891Swpaul	 */
44712891Swpaul	result.more = TRUE;
44812891Swpaul
44912891Swpaul	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
45012891Swpaul		result.ypresp_all_u.val.stat = YP_YPERR;
45112891Swpaul		return (&result);
45212891Swpaul	}
45312891Swpaul
45412891Swpaul	if (argp->domain == NULL || argp->map == NULL) {
45512891Swpaul		result.ypresp_all_u.val.stat = YP_BADARGS;
45612891Swpaul		return (&result);
45712891Swpaul	}
45812891Swpaul
45912891Swpaul	if (yp_validdomain(argp->domain)) {
46012891Swpaul		result.ypresp_all_u.val.stat = YP_NODOM;
46112891Swpaul		return(&result);
46212891Swpaul	}
46312891Swpaul
46412891Swpaul	/*
46512891Swpaul	 * The ypproc_all procedure can take a while to complete.
46612891Swpaul	 * Best to handle it in a subprocess so the parent doesn't
46712891Swpaul	 * block. We fork() here so we don't end up sharing a
46812891Swpaul	 * DB file handle with the parent.
46912891Swpaul	 */
47012891Swpaul
47112891Swpaul	if (!debug && children < MAX_CHILDREN && fork()) {
47212891Swpaul		children++;
47312891Swpaul		forked = 0;
47412891Swpaul		return (NULL);
47512891Swpaul	} else {
47612891Swpaul		forked++;
47712891Swpaul	}
47812891Swpaul
47912891Swpaul	if ((spec_dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
48012891Swpaul		result.ypresp_all_u.val.stat = yp_errno;
48112891Swpaul		return(&result);
48212891Swpaul	}
48312891Swpaul
48412891Swpaul	/* Kick off the actual data transfer. */
48512891Swpaul	svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result);
48612891Swpaul
48712891Swpaul	/* Close database when done. */
48812891Swpaul	(void)(spec_dbp->close)(spec_dbp);
48912891Swpaul
49012891Swpaul	/*
49112891Swpaul	 * Returning NULL prevents the dispatcher from calling
49212891Swpaul	 * svc_sendreply() since we already did it.
49312891Swpaul	 */
49412891Swpaul	return (NULL);
49512891Swpaul}
49612891Swpaul
49712891Swpaulypresp_master *
49812891Swpaulypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
49912891Swpaul{
50012891Swpaul	static ypresp_master  result;
50112891Swpaul	DBT key,data;
50212891Swpaul
50312891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
50412891Swpaul		result.stat = YP_YPERR;
50512891Swpaul		return(&result);
50612891Swpaul	}
50712891Swpaul
50812891Swpaul	if (argp->domain == NULL) {
50912891Swpaul		result.stat = YP_BADARGS;
51012891Swpaul		return (&result);
51112891Swpaul	}
51212891Swpaul
51312891Swpaul	if (yp_validdomain(argp->domain)) {
51412891Swpaul		result.stat = YP_NODOM;
51512891Swpaul		return (&result);
51612891Swpaul	}
51712891Swpaul
51812891Swpaul	key.data = "YP_MASTER_NAME";
51912891Swpaul	key.size = sizeof("YP_MASTER_NAME") - 1;
52012891Swpaul
52112891Swpaul	result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 1);
52212891Swpaul
52312891Swpaul	if (result.stat == YP_TRUE) {
52412891Swpaul		result.peer = (char *)data.data;
52512891Swpaul		result.peer[data.size] = '\0';
52612891Swpaul	} else
52712891Swpaul		result.peer = "";
52812891Swpaul
52912891Swpaul	return (&result);
53012891Swpaul}
53112891Swpaul
53212891Swpaulypresp_order *
53312891Swpaulypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
53412891Swpaul{
53512891Swpaul	static ypresp_order  result;
53612891Swpaul	DBT key,data;
53712891Swpaul
53812891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
53912891Swpaul		result.stat = YP_YPERR;
54012891Swpaul		return(&result);
54112891Swpaul	}
54212891Swpaul
54312891Swpaul	if (argp->domain == NULL) {
54412891Swpaul		result.stat = YP_BADARGS;
54512891Swpaul		return (&result);
54612891Swpaul	}
54712891Swpaul
54812891Swpaul	if (yp_validdomain(argp->domain)) {
54912891Swpaul		result.stat = YP_NODOM;
55012891Swpaul		return (&result);
55112891Swpaul	}
55212891Swpaul
55312891Swpaul	/*
55412891Swpaul	 * We could just check the timestamp on the map file,
55512891Swpaul	 * but that's a hack: we'll only know the last time the file
55612891Swpaul	 * was touched, not the last time the database contents were
55712891Swpaul	 * updated.
55812891Swpaul	 */
55912891Swpaul	key.data = "YP_LAST_MODIFIED";
56012891Swpaul	key.size = sizeof("YP_LAST_MODIFIED") - 1;
56112891Swpaul
56212891Swpaul	result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 1);
56312891Swpaul
56412891Swpaul	if (result.stat == YP_TRUE)
56512891Swpaul		result.ordernum = atoi((char *)data.data);
56612891Swpaul	else
56712891Swpaul		result.ordernum = 0;
56812891Swpaul
56912891Swpaul	return (&result);
57012891Swpaul}
57112891Swpaul
57212891Swpaulstatic void yp_maplist_free(yp_maplist)
57312891Swpaul	struct ypmaplist *yp_maplist;
57412891Swpaul{
57512891Swpaul	register struct ypmaplist *next;
57612891Swpaul
57712891Swpaul	while(yp_maplist) {
57812891Swpaul		next = yp_maplist->next;
57912891Swpaul		free(yp_maplist->map);
58012891Swpaul		free(yp_maplist);
58112891Swpaul		yp_maplist = next;
58212891Swpaul	}
58312891Swpaul	return;
58412891Swpaul}
58512891Swpaul
58612891Swpaulstatic struct ypmaplist *yp_maplist_create(domain)
58712891Swpaul	const char *domain;
58812891Swpaul{
58912891Swpaul	char yp_mapdir[MAXPATHLEN + 2];
59012891Swpaul	char yp_mapname[MAXPATHLEN + 2];
59112891Swpaul	struct ypmaplist *cur = NULL;
59212891Swpaul	struct ypmaplist *yp_maplist = NULL;
59312891Swpaul	DIR *dird;
59412891Swpaul	struct dirent *dirp;
59512891Swpaul	struct stat statbuf;
59612891Swpaul
59712891Swpaul	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
59812891Swpaul
59912891Swpaul	if ((dird = opendir(yp_mapdir)) == NULL) {
60012891Swpaul		yp_error("opendir(%s) failed: %s", strerror(errno));
60112891Swpaul		return(NULL);
60212891Swpaul	}
60312891Swpaul
60412891Swpaul	while ((dirp = readdir(dird)) != NULL) {
60512891Swpaul		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
60612891Swpaul			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",yp_mapdir,dirp->d_name);
60712891Swpaul			if (stat(yp_mapname, &statbuf) < 0 || !S_ISREG(statbuf.st_mode))
60812891Swpaul				continue;
60912891Swpaul			if ((cur = (struct ypmaplist *)malloc(sizeof(struct ypmaplist))) < 0) {
61012891Swpaul				yp_error("malloc() failed: %s", strerror(errno));
61112891Swpaul				closedir(dird);
61212891Swpaul				yp_maplist_free(yp_maplist);
61312891Swpaul				return(NULL);
61412891Swpaul			}
61512891Swpaul			if ((cur->map = (char *)strdup(dirp->d_name)) == NULL) {
61612891Swpaul				yp_error("strdup() failed: %s", strerror(errno));
61712891Swpaul				closedir(dird);
61812891Swpaul				yp_maplist_free(yp_maplist);
61912891Swpaul				return(NULL);
62012891Swpaul			}
62112891Swpaul			cur->next = yp_maplist;
62212891Swpaul			yp_maplist = cur;
62312891Swpaul			if (debug)
62412891Swpaul				yp_error("map: %s", yp_maplist->map);
62512891Swpaul		}
62612891Swpaul
62712891Swpaul	}
62812891Swpaul	closedir(dird);
62912891Swpaul	return(yp_maplist);
63012891Swpaul}
63112891Swpaul
63212891Swpaulypresp_maplist *
63312891Swpaulypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
63412891Swpaul{
63512891Swpaul	static ypresp_maplist  result;
63612891Swpaul
63712891Swpaul	if (yp_access(NULL, (struct svc_req *)rqstp)) {
63812891Swpaul		result.stat = YP_YPERR;
63912891Swpaul		return(&result);
64012891Swpaul	}
64112891Swpaul
64212891Swpaul	if (argp == NULL) {
64312891Swpaul		result.stat = YP_BADARGS;
64412891Swpaul		return (&result);
64512891Swpaul	}
64612891Swpaul
64712891Swpaul	if (yp_validdomain(*argp)) {
64812891Swpaul		result.stat = YP_NODOM;
64912891Swpaul		return (&result);
65012891Swpaul	}
65112891Swpaul
65212891Swpaul	/*
65312891Swpaul	 * We have to construct a linked list for the ypproc_maplist
65412891Swpaul	 * procedure using dynamically allocated memory. Since the XDR
65512891Swpaul	 * layer won't free this list for us, we have to deal with it
65612891Swpaul	 * ourselves. We call yp_maplist_free() first to free any
65712891Swpaul	 * previously allocated data we may have accumulated to insure
65812891Swpaul	 * that we have only one linked list in memory at any given
65912891Swpaul	 * time.
66012891Swpaul	 */
66112891Swpaul
66212891Swpaul	yp_maplist_free(result.maps);
66312891Swpaul
66412891Swpaul	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
66512891Swpaul		yp_error("yp_maplist_create failed");
66612891Swpaul		result.stat = YP_YPERR;
66712891Swpaul		return(&result);
66812891Swpaul	} else
66912891Swpaul		result.stat = YP_TRUE;
67012891Swpaul
67112891Swpaul	return (&result);
67212891Swpaul}
673