yp_server.c revision 90298
1251881Speter/*
2251881Speter * Copyright (c) 1995
3251881Speter *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4251881Speter *
5251881Speter * Redistribution and use in source and binary forms, with or without
6251881Speter * modification, are permitted provided that the following conditions
7251881Speter * are met:
8251881Speter * 1. Redistributions of source code must retain the above copyright
9251881Speter *    notice, this list of conditions and the following disclaimer.
10251881Speter * 2. Redistributions in binary form must reproduce the above copyright
11251881Speter *    notice, this list of conditions and the following disclaimer in the
12251881Speter *    documentation and/or other materials provided with the distribution.
13251881Speter * 3. All advertising materials mentioning features or use of this software
14251881Speter *    must display the following acknowledgement:
15251881Speter *	This product includes software developed by Bill Paul.
16251881Speter * 4. Neither the name of the author nor the names of any co-contributors
17251881Speter *    may be used to endorse or promote products derived from this software
18251881Speter *    without specific prior written permission.
19251881Speter *
20251881Speter * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30251881Speter * SUCH DAMAGE.
31251881Speter *
32251881Speter */
33251881Speter
34251881Speter#ifndef lint
35251881Speterstatic const char rcsid[] =
36251881Speter  "$FreeBSD: head/usr.sbin/ypserv/yp_server.c 90298 2002-02-06 15:26:07Z des $";
37251881Speter#endif /* not lint */
38251881Speter
39251881Speter#include "yp.h"
40251881Speter#include "yp_extern.h"
41251881Speter#include <dirent.h>
42251881Speter#include <errno.h>
43251881Speter#include <stdlib.h>
44251881Speter#include <sys/stat.h>
45251881Speter#include <sys/param.h>
46251881Speter#include <sys/types.h>
47251881Speter#include <sys/socket.h>
48251881Speter#include <netinet/in.h>
49251881Speter#include <arpa/inet.h>
50251881Speter#include <rpc/rpc.h>
51251881Speter
52251881Speterint children = 0;
53251881Speter
54251881Speter#define	MASTER_STRING	"YP_MASTER_NAME"
55251881Speter#define	MASTER_SZ	sizeof(MASTER_STRING) - 1
56251881Speter#define	ORDER_STRING	"YP_LAST_MODIFIED"
57251881Speter#define	ORDER_SZ	sizeof(ORDER_STRING) - 1
58251881Speter
59251881Speterstatic pid_t
60251881Speteryp_fork(void)
61251881Speter{
62251881Speter	if (yp_pid != getpid()) {
63251881Speter		yp_error("child %d trying to fork!", getpid());
64251881Speter		errno = EEXIST;
65251881Speter		return(-1);
66251881Speter	}
67251881Speter
68251881Speter	return(fork());
69251881Speter}
70251881Speter
71251881Speter/*
72251881Speter * NIS v2 support. This is where most of the action happens.
73251881Speter */
74251881Speter
75251881Spetervoid *
76251881Speterypproc_null_2_svc(void *argp, struct svc_req *rqstp)
77251881Speter{
78251881Speter	static char * result;
79251881Speter	static char rval = 0;
80251881Speter
81251881Speter#ifdef DB_CACHE
82251881Speter	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
83251881Speter#else
84251881Speter	if (yp_access(NULL, (struct svc_req *)rqstp))
85251881Speter#endif
86251881Speter		return(NULL);
87251881Speter
88251881Speter	result = &rval;
89251881Speter
90251881Speter	return((void *) &result);
91251881Speter}
92251881Speter
93251881Speterbool_t *
94251881Speterypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
95251881Speter{
96251881Speter	static bool_t  result;
97251881Speter
98251881Speter#ifdef DB_CACHE
99251881Speter	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
100251881Speter#else
101251881Speter	if (yp_access(NULL, (struct svc_req *)rqstp)) {
102251881Speter#endif
103251881Speter		result = FALSE;
104251881Speter		return (&result);
105251881Speter	}
106251881Speter
107251881Speter	if (argp == NULL || yp_validdomain(*argp))
108251881Speter		result = FALSE;
109251881Speter	else
110251881Speter		result = TRUE;
111251881Speter
112251881Speter	return (&result);
113251881Speter}
114251881Speter
115251881Speterbool_t *
116251881Speterypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
117251881Speter{
118251881Speter	static bool_t  result;
119251881Speter
120251881Speter#ifdef DB_CACHE
121251881Speter	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
122251881Speter#else
123251881Speter	if (yp_access(NULL, (struct svc_req *)rqstp))
124251881Speter#endif
125251881Speter		return (NULL);
126251881Speter
127251881Speter	if (argp == NULL || yp_validdomain(*argp))
128251881Speter		return (NULL);
129251881Speter	else
130251881Speter		result = TRUE;
131251881Speter
132251881Speter	return (&result);
133251881Speter}
134251881Speter
135251881Speterypresp_val *
136251881Speterypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
137251881Speter{
138251881Speter	static ypresp_val  result;
139251881Speter
140251881Speter	result.val.valdat_val = "";
141251881Speter	result.val.valdat_len = 0;
142251881Speter
143251881Speter#ifdef DB_CACHE
144251881Speter	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
145251881Speter#else
146251881Speter	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
147251881Speter#endif
148251881Speter		result.stat = YP_YPERR;
149251881Speter		return (&result);
150251881Speter	}
151251881Speter
152251881Speter	if (argp->domain == NULL || argp->map == NULL) {
153251881Speter		result.stat = YP_BADARGS;
154251881Speter		return (&result);
155251881Speter	}
156251881Speter
157251881Speter	if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) {
158251881Speter		result.stat = yp_errno;
159251881Speter		return(&result);
160251881Speter	}
161251881Speter
162251881Speter	result.stat = yp_getbykey(&argp->key, &result.val);
163251881Speter
164251881Speter	/*
165251881Speter	 * Do DNS lookups for hosts maps if database lookup failed.
166251881Speter	 */
167251881Speter
168251881Speter#ifdef DB_CACHE
169251881Speter	if (result.stat != YP_TRUE &&
170251881Speter	    (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) ||
171251881Speter	    (strstr(argp->map, "hosts") && do_dns))) {
172251881Speter#else
173251881Speter	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
174251881Speter#endif
175251881Speter		char			nbuf[YPMAXRECORD];
176251881Speter
177251881Speter		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
178251881Speter		bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len);
179251881Speter		nbuf[argp->key.keydat_len] = '\0';
180251881Speter
181251881Speter		if (debug)
182251881Speter			yp_error("doing DNS lookup of %s", nbuf);
183251881Speter
184251881Speter		if (!strcmp(argp->map, "hosts.byname"))
185251881Speter			result.stat = yp_async_lookup_name(rqstp, nbuf);
186251881Speter		else if (!strcmp(argp->map, "hosts.byaddr"))
187251881Speter			result.stat = yp_async_lookup_addr(rqstp, nbuf);
188251881Speter
189251881Speter		if (result.stat == YP_TRUE)
190251881Speter			return(NULL);
191251881Speter	}
192251881Speter
193251881Speter	return (&result);
194251881Speter}
195251881Speter
196251881Speterypresp_key_val *
197251881Speterypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
198251881Speter{
199251881Speter	static ypresp_key_val  result;
200251881Speter
201251881Speter	result.val.valdat_val = result.key.keydat_val = "";
202251881Speter	result.val.valdat_len = result.key.keydat_len = 0;
203251881Speter
204251881Speter#ifdef DB_CACHE
205251881Speter	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
206251881Speter#else
207251881Speter	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
208251881Speter#endif
209251881Speter		result.stat = YP_YPERR;
210251881Speter		return (&result);
211251881Speter	}
212251881Speter
213251881Speter	if (argp->domain == NULL) {
214251881Speter		result.stat = YP_BADARGS;
215251881Speter		return (&result);
216251881Speter	}
217251881Speter
218251881Speter	if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) {
219251881Speter		result.stat = yp_errno;
220251881Speter		return(&result);
221251881Speter	}
222251881Speter
223251881Speter	result.stat = yp_firstbykey(&result.key, &result.val);
224251881Speter
225251881Speter	return (&result);
226251881Speter}
227251881Speter
228251881Speterypresp_key_val *
229251881Speterypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
230251881Speter{
231251881Speter	static ypresp_key_val  result;
232251881Speter
233251881Speter	result.val.valdat_val = result.key.keydat_val = "";
234251881Speter	result.val.valdat_len = result.key.keydat_len = 0;
235251881Speter
236251881Speter#ifdef DB_CACHE
237251881Speter	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
238251881Speter#else
239251881Speter	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
240251881Speter#endif
241251881Speter		result.stat = YP_YPERR;
242251881Speter		return (&result);
243251881Speter	}
244251881Speter
245251881Speter	if (argp->domain == NULL || argp->map == NULL) {
246251881Speter		result.stat = YP_BADARGS;
247251881Speter		return (&result);
248251881Speter	}
249251881Speter
250251881Speter	if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) {
251251881Speter		result.stat = yp_errno;
252251881Speter		return(&result);
253251881Speter	}
254251881Speter
255251881Speter	result.key.keydat_len = argp->key.keydat_len;
256251881Speter	result.key.keydat_val = argp->key.keydat_val;
257251881Speter
258251881Speter	result.stat = yp_nextbykey(&result.key, &result.val);
259251881Speter
260251881Speter	return (&result);
261251881Speter}
262251881Speter
263251881Speterstatic void
264251881Speterypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid,
265251881Speter    unsigned int prognum, unsigned long port)
266251881Speter{
267251881Speter	CLIENT *clnt;
268251881Speter	int sock = RPC_ANYSOCK;
269251881Speter	struct timeval timeout;
270251881Speter	yppushresp_xfr ypxfr_resp;
271251881Speter	struct rpc_err err;
272251881Speter
273251881Speter	timeout.tv_sec = 5;
274251881Speter	timeout.tv_usec = 0;
275251881Speter	addr->sin_port = htons(port);
276251881Speter
277251881Speter	if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) {
278251881Speter		yp_error("%s: %s", inet_ntoa(addr->sin_addr),
279251881Speter		  clnt_spcreateerror("failed to establish callback handle"));
280251881Speter		return;
281251881Speter	}
282251881Speter
283251881Speter	ypxfr_resp.status = rval;
284251881Speter	ypxfr_resp.transid = transid;
285251881Speter
286251881Speter	/* Turn the timeout off -- we don't want to block. */
287251881Speter	timeout.tv_sec = 0;
288251881Speter	if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE)
289251881Speter		yp_error("failed to set timeout on ypproc_xfr callback");
290251881Speter
291251881Speter	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
292251881Speter		clnt_geterr(clnt, &err);
293251881Speter		if (err.re_status != RPC_SUCCESS &&
294251881Speter		    err.re_status != RPC_TIMEDOUT)
295251881Speter			yp_error("%s", clnt_sperror(clnt,
296251881Speter				"ypxfr callback failed"));
297251881Speter	}
298251881Speter
299251881Speter	clnt_destroy(clnt);
300251881Speter	return;
301251881Speter}
302251881Speter
303251881Speter#define YPXFR_RETURN(CODE) 						\
304251881Speter	/* Order is important: send regular RPC reply, then callback */	\
305251881Speter	result.xfrstat = CODE; 						\
306251881Speter	svc_sendreply(rqstp->rq_xprt, xdr_ypresp_xfr, (char *)&result); \
307251881Speter	ypxfr_callback(CODE,rqhost,argp->transid, 			\
308251881Speter					argp->prog,argp->port); 	\
309251881Speter	return(NULL);
310251881Speter
311251881Speterypresp_xfr *
312251881Speterypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
313251881Speter{
314251881Speter	static ypresp_xfr  result;
315251881Speter	struct sockaddr_in *rqhost;
316251881Speter	ypresp_master *mres;
317251881Speter	ypreq_nokey mreq;
318251881Speter
319251881Speter	result.transid = argp->transid;
320251881Speter	rqhost = svc_getcaller(rqstp->rq_xprt);
321251881Speter
322251881Speter#ifdef DB_CACHE
323251881Speter	if (yp_access(argp->map_parms.map,
324251881Speter			argp->map_parms.domain, (struct svc_req *)rqstp)) {
325251881Speter#else
326251881Speter	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
327251881Speter#endif
328251881Speter		YPXFR_RETURN(YPXFR_REFUSED)
329251881Speter	}
330251881Speter
331251881Speter
332251881Speter	if (argp->map_parms.domain == NULL) {
333251881Speter		YPXFR_RETURN(YPXFR_BADARGS)
334251881Speter	}
335251881Speter
336251881Speter	if (yp_validdomain(argp->map_parms.domain)) {
337251881Speter		YPXFR_RETURN(YPXFR_NODOM)
338251881Speter	}
339251881Speter
340251881Speter	/*
341251881Speter	 * Determine the master host ourselves. The caller may
342251881Speter	 * be up to no good. This has the side effect of verifying
343251881Speter	 * that the requested map and domain actually exist.
344251881Speter	 */
345251881Speter
346251881Speter	mreq.domain = argp->map_parms.domain;
347251881Speter	mreq.map = argp->map_parms.map;
348251881Speter
349251881Speter	mres = ypproc_master_2_svc(&mreq, rqstp);
350251881Speter
351251881Speter	if (mres->stat != YP_TRUE) {
352251881Speter		yp_error("couldn't find master for map %s@%s",
353251881Speter						argp->map_parms.map,
354251881Speter						argp->map_parms.domain);
355251881Speter		yp_error("host at %s (%s) may be pulling my leg",
356251881Speter						argp->map_parms.peer,
357251881Speter						inet_ntoa(rqhost->sin_addr));
358251881Speter		YPXFR_RETURN(YPXFR_REFUSED)
359251881Speter	}
360251881Speter
361251881Speter	switch (yp_fork()) {
362251881Speter	case 0:
363251881Speter	{
364251881Speter		char g[11], t[11], p[11];
365251881Speter		char ypxfr_command[MAXPATHLEN + 2];
366251881Speter
367251881Speter		snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC);
368251881Speter		snprintf (t, sizeof(t), "%u", argp->transid);
369251881Speter		snprintf (g, sizeof(g), "%u", argp->prog);
370251881Speter		snprintf (p, sizeof(p), "%u", argp->port);
371251881Speter		if (debug) {
372251881Speter			close(0); close(1); close(2);
373251881Speter		}
374251881Speter		if (strcmp(yp_dir, _PATH_YP)) {
375251881Speter			execl(ypxfr_command, "ypxfr",
376251881Speter			"-d", argp->map_parms.domain,
377251881Speter		      	"-h", mres->peer,
378251881Speter			"-p", yp_dir, "-C", t,
379251881Speter		      	g, inet_ntoa(rqhost->sin_addr),
380251881Speter			p, argp->map_parms.map,
381251881Speter		      	(char *)NULL);
382251881Speter		} else {
383251881Speter			execl(ypxfr_command, "ypxfr",
384251881Speter			"-d", argp->map_parms.domain,
385251881Speter		      	"-h", mres->peer,
386251881Speter			"-C", t,
387251881Speter		      	g, inet_ntoa(rqhost->sin_addr),
388251881Speter			p, argp->map_parms.map,
389251881Speter		      	(char *)NULL);
390251881Speter		}
391251881Speter		yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
392251881Speter		YPXFR_RETURN(YPXFR_XFRERR)
393251881Speter		/*
394251881Speter		 * Just to safe, prevent PR #10970 from biting us in
395251881Speter		 * the unlikely case that execing ypxfr fails. We don't
396251881Speter		 * want to have any child processes spawned from this
397251881Speter		 * child process.
398251881Speter		 */
399251881Speter		_exit(0);
400251881Speter		break;
401251881Speter	}
402251881Speter	case -1:
403251881Speter		yp_error("ypxfr fork(): %s", strerror(errno));
404251881Speter		YPXFR_RETURN(YPXFR_XFRERR)
405251881Speter		break;
406251881Speter	default:
407251881Speter		result.xfrstat = YPXFR_SUCC;
408251881Speter		children++;
409251881Speter		break;
410251881Speter	}
411251881Speter
412251881Speter	return (&result);
413251881Speter}
414251881Speter#undef YPXFR_RETURN
415251881Speter
416251881Spetervoid *
417251881Speterypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
418251881Speter{
419251881Speter	static char * result;
420251881Speter	static char rval = 0;
421251881Speter
422251881Speter#ifdef DB_CACHE
423251881Speter	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
424251881Speter#else
425251881Speter	if (yp_access(NULL, (struct svc_req *)rqstp))
426251881Speter#endif
427251881Speter		return (NULL);
428251881Speter#ifdef DB_CACHE
429251881Speter	/* clear out the database cache */
430251881Speter	yp_flush_all();
431#endif
432	/* Re-read the securenets database for the hell of it. */
433	load_securenets();
434
435	result = &rval;
436	return((void *) &result);
437}
438
439/*
440 * For ypproc_all, we have to send a stream of ypresp_all structures
441 * via TCP, but the XDR filter generated from the yp.x protocol
442 * definition file only serializes one such structure. This means that
443 * to send the whole stream, you need a wrapper which feeds all the
444 * records into the underlying XDR routine until it hits an 'EOF.'
445 * But to use the wrapper, you have to violate the boundaries between
446 * RPC layers by calling svc_sendreply() directly from the ypproc_all
447 * service routine instead of letting the RPC dispatcher do it.
448 *
449 * Bleah.
450 */
451
452/*
453 * Custom XDR routine for serialzing results of ypproc_all: keep
454 * reading from the database and spew until we run out of records
455 * or encounter an error.
456 */
457static bool_t
458xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
459{
460	while (1) {
461		/* Get a record. */
462		if ((objp->ypresp_all_u.val.stat =
463			yp_nextbykey(&objp->ypresp_all_u.val.key,
464				     &objp->ypresp_all_u.val.val)) == YP_TRUE) {
465			objp->more = TRUE;
466		} else {
467			objp->more = FALSE;
468		}
469
470		/* Serialize. */
471		if (!xdr_ypresp_all(xdrs, objp))
472			return(FALSE);
473		if (objp->more == FALSE)
474			return(TRUE);
475	}
476}
477
478ypresp_all *
479ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
480{
481	static ypresp_all  result;
482
483	/*
484	 * Set this here so that the client will be forced to make
485	 * at least one attempt to read from us even if all we're
486	 * doing is returning an error.
487	 */
488	result.more = TRUE;
489	result.ypresp_all_u.val.key.keydat_len = 0;
490	result.ypresp_all_u.val.key.keydat_val = "";
491
492#ifdef DB_CACHE
493	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
494#else
495	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
496#endif
497		result.ypresp_all_u.val.stat = YP_YPERR;
498		return (&result);
499	}
500
501	if (argp->domain == NULL || argp->map == NULL) {
502		result.ypresp_all_u.val.stat = YP_BADARGS;
503		return (&result);
504	}
505
506	/*
507	 * XXX If we hit the child limit, fail the request.
508	 * If we don't, and the map is large, we could block for
509	 * a long time in the parent.
510	 */
511	if (children >= MAX_CHILDREN) {
512		result.ypresp_all_u.val.stat = YP_YPERR;
513		return(&result);
514	}
515
516	/*
517	 * The ypproc_all procedure can take a while to complete.
518	 * Best to handle it in a subprocess so the parent doesn't
519	 * block. (Is there a better way to do this? Maybe with
520	 * async socket I/O?)
521	 */
522	if (!debug) {
523		switch (yp_fork()) {
524		case 0:
525			break;
526		case -1:
527			yp_error("ypall fork(): %s", strerror(errno));
528			result.ypresp_all_u.val.stat = YP_YPERR;
529			return(&result);
530			break;
531		default:
532			children++;
533			return (NULL);
534			break;
535		}
536	}
537
538	/*
539	 * Fix for PR #10971: don't let the child ypserv share
540	 * DB handles with the parent process.
541	 */
542#ifdef DB_CACHE
543	yp_flush_all();
544#endif
545
546	if (yp_select_map(argp->map, argp->domain,
547				&result.ypresp_all_u.val.key, 0) != YP_TRUE) {
548		result.ypresp_all_u.val.stat = yp_errno;
549		return(&result);
550	}
551
552	/* Kick off the actual data transfer. */
553	svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result);
554
555	/*
556	 * Proper fix for PR #10970: exit here so that we don't risk
557	 * having a child spawned from this sub-process.
558	 */
559	_exit(0);
560}
561
562ypresp_master *
563ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
564{
565	static ypresp_master  result;
566	static char ypvalbuf[YPMAXRECORD];
567	keydat key = { MASTER_SZ, MASTER_STRING };
568	valdat val;
569
570	result.peer = "";
571
572#ifdef DB_CACHE
573	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
574#else
575	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
576#endif
577		result.stat = YP_YPERR;
578		return(&result);
579	}
580
581	if (argp->domain == NULL) {
582		result.stat = YP_BADARGS;
583		return (&result);
584	}
585
586	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
587		result.stat = yp_errno;
588		return(&result);
589	}
590
591	/*
592	 * Note that we copy the data retrieved from the database to
593	 * a private buffer and NUL terminate the buffer rather than
594	 * terminating the data in place. We do this because by stuffing
595	 * a '\0' into data.data, we will actually be corrupting memory
596	 * allocated by the DB package. This is a bad thing now that we
597	 * cache DB handles rather than closing the database immediately.
598	 */
599	result.stat = yp_getbykey(&key, &val);
600	if (result.stat == YP_TRUE) {
601		bcopy((char *)val.valdat_val, (char *)&ypvalbuf,
602						val.valdat_len);
603		ypvalbuf[val.valdat_len] = '\0';
604		result.peer = (char *)&ypvalbuf;
605	} else
606		result.peer = "";
607
608	return (&result);
609}
610
611ypresp_order *
612ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
613{
614	static ypresp_order  result;
615	keydat key = { ORDER_SZ, ORDER_STRING };
616	valdat val;
617
618	result.ordernum = 0;
619
620#ifdef DB_CACHE
621	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
622#else
623	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
624#endif
625		result.stat = YP_YPERR;
626		return(&result);
627	}
628
629	if (argp->domain == NULL) {
630		result.stat = YP_BADARGS;
631		return (&result);
632	}
633
634	/*
635	 * We could just check the timestamp on the map file,
636	 * but that's a hack: we'll only know the last time the file
637	 * was touched, not the last time the database contents were
638	 * updated.
639	 */
640
641	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
642		result.stat = yp_errno;
643		return(&result);
644	}
645
646	result.stat = yp_getbykey(&key, &val);
647
648	if (result.stat == YP_TRUE)
649		result.ordernum = atoi((char *)val.valdat_val);
650	else
651		result.ordernum = 0;
652
653	return (&result);
654}
655
656static void yp_maplist_free(struct ypmaplist *yp_maplist)
657{
658	register struct ypmaplist *next;
659
660	while (yp_maplist) {
661		next = yp_maplist->next;
662		free(yp_maplist->map);
663		free(yp_maplist);
664		yp_maplist = next;
665	}
666	return;
667}
668
669static struct ypmaplist *
670yp_maplist_create(const char *domain)
671{
672	char yp_mapdir[MAXPATHLEN + 2];
673	char yp_mapname[MAXPATHLEN + 2];
674	struct ypmaplist *cur = NULL;
675	struct ypmaplist *yp_maplist = NULL;
676	DIR *dird;
677	struct dirent *dirp;
678	struct stat statbuf;
679
680	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
681
682	if ((dird = opendir(yp_mapdir)) == NULL) {
683		yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno));
684		return(NULL);
685	}
686
687	while ((dirp = readdir(dird)) != NULL) {
688		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
689			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",
690							yp_mapdir,dirp->d_name);
691			if (stat(yp_mapname, &statbuf) < 0 ||
692						!S_ISREG(statbuf.st_mode))
693				continue;
694			if ((cur = (struct ypmaplist *)
695				malloc(sizeof(struct ypmaplist))) == NULL) {
696				yp_error("malloc() failed");
697				closedir(dird);
698				yp_maplist_free(yp_maplist);
699				return(NULL);
700			}
701			if ((cur->map = (char *)strdup(dirp->d_name)) == NULL) {
702				yp_error("strdup() failed: %s",strerror(errno));
703				closedir(dird);
704				yp_maplist_free(yp_maplist);
705				return(NULL);
706			}
707			cur->next = yp_maplist;
708			yp_maplist = cur;
709			if (debug)
710				yp_error("map: %s", yp_maplist->map);
711		}
712
713	}
714	closedir(dird);
715	return(yp_maplist);
716}
717
718ypresp_maplist *
719ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
720{
721	static ypresp_maplist  result = { 0, NULL };
722
723#ifdef DB_CACHE
724	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
725#else
726	if (yp_access(NULL, (struct svc_req *)rqstp)) {
727#endif
728		result.stat = YP_YPERR;
729		return(&result);
730	}
731
732	if (argp == NULL) {
733		result.stat = YP_BADARGS;
734		return (&result);
735	}
736
737	if (yp_validdomain(*argp)) {
738		result.stat = YP_NODOM;
739		return (&result);
740	}
741
742	/*
743	 * We have to construct a linked list for the ypproc_maplist
744	 * procedure using dynamically allocated memory. Since the XDR
745	 * layer won't free this list for us, we have to deal with it
746	 * ourselves. We call yp_maplist_free() first to free any
747	 * previously allocated data we may have accumulated to insure
748	 * that we have only one linked list in memory at any given
749	 * time.
750	 */
751
752	yp_maplist_free(result.maps);
753
754	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
755		yp_error("yp_maplist_create failed");
756		result.stat = YP_YPERR;
757		return(&result);
758	} else
759		result.stat = YP_TRUE;
760
761	return (&result);
762}
763
764/*
765 * NIS v1 support. The nullproc, domain and domain_nonack
766 * functions from v1 are identical to those in v2, so all
767 * we have to do is hand off to them.
768 *
769 * The other functions are mostly just wrappers around their v2
770 * counterparts. For example, for the v1 'match' procedure, we
771 * crack open the argument structure, make a request to the v2
772 * 'match' function, repackage the data into a v1 response and
773 * then send it on its way.
774 *
775 * Note that we don't support the pull, push and get procedures.
776 * There's little documentation available to show what they
777 * do, and I suspect they're meant largely for map transfers
778 * between master and slave servers.
779 */
780
781void *
782ypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
783{
784	return(ypproc_null_2_svc(argp, rqstp));
785}
786
787bool_t *
788ypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
789{
790	return(ypproc_domain_2_svc(argp, rqstp));
791}
792
793bool_t *
794ypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
795{
796	return (ypproc_domain_nonack_2_svc(argp, rqstp));
797}
798
799/*
800 * the 'match' procedure sends a response of type YPRESP_VAL
801 */
802ypresponse *
803ypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
804{
805	static ypresponse  result;
806	ypresp_val *v2_result;
807
808	result.yp_resptype = YPRESP_VAL;
809	result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
810	result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
811
812	if (argp->yp_reqtype != YPREQ_KEY) {
813		result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
814		return(&result);
815	}
816
817	v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
818	if (v2_result == NULL)
819		return(NULL);
820
821	bcopy((char *)v2_result,
822	      (char *)&result.ypresponse_u.yp_resp_valtype,
823	      sizeof(ypresp_val));
824
825	return (&result);
826}
827
828/*
829 * the 'first' procedure sends a response of type YPRESP_KEY_VAL
830 */
831ypresponse *
832ypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
833{
834	static ypresponse  result;
835	ypresp_key_val *v2_result;
836
837	result.yp_resptype = YPRESP_KEY_VAL;
838	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
839	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
840	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
841	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
842
843	if (argp->yp_reqtype != YPREQ_NOKEY) {
844		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
845		return(&result);
846	}
847
848	v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
849									rqstp);
850	if (v2_result == NULL)
851		return(NULL);
852
853	bcopy((char *)v2_result,
854	      (char *)&result.ypresponse_u.yp_resp_key_valtype,
855	      sizeof(ypresp_key_val));
856
857	return (&result);
858}
859
860/*
861 * the 'next' procedure sends a response of type YPRESP_KEY_VAL
862 */
863ypresponse *
864ypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
865{
866	static ypresponse  result;
867	ypresp_key_val *v2_result;
868
869	result.yp_resptype = YPRESP_KEY_VAL;
870	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
871	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
872	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
873	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
874
875	if (argp->yp_reqtype != YPREQ_KEY) {
876		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
877		return(&result);
878	}
879
880	v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
881	if (v2_result == NULL)
882		return(NULL);
883
884	bcopy((char *)v2_result,
885	      (char *)&result.ypresponse_u.yp_resp_key_valtype,
886	      sizeof(ypresp_key_val));
887
888	return (&result);
889}
890
891/*
892 * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
893 */
894ypresponse *
895ypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
896{
897	static ypresponse  result;
898	ypresp_master *v2_result1;
899	ypresp_order *v2_result2;
900
901	result.yp_resptype = YPRESP_MAP_PARMS;
902	result.ypresponse_u.yp_resp_map_parmstype.domain =
903		argp->yprequest_u.yp_req_nokeytype.domain;
904	result.ypresponse_u.yp_resp_map_parmstype.map =
905		argp->yprequest_u.yp_req_nokeytype.map;
906	/*
907	 * Hmm... there is no 'status' value in the
908	 * yp_resp_map_parmstype structure, so I have to
909	 * guess at what to do to indicate a failure.
910	 * I hope this is right.
911	 */
912	result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
913	result.ypresponse_u.yp_resp_map_parmstype.peer = "";
914
915	if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
916		return(&result);
917	}
918
919	v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
920									rqstp);
921	if (v2_result1 == NULL)
922		return(NULL);
923
924	if (v2_result1->stat != YP_TRUE) {
925		return(&result);
926	}
927
928	v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
929									rqstp);
930	if (v2_result2 == NULL)
931		return(NULL);
932
933	if (v2_result2->stat != YP_TRUE) {
934		return(&result);
935	}
936
937	result.ypresponse_u.yp_resp_map_parmstype.peer =
938		v2_result1->peer;
939	result.ypresponse_u.yp_resp_map_parmstype.ordernum =
940		v2_result2->ordernum;
941
942	return (&result);
943}
944
945ypresponse *
946ypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
947{
948	static ypresponse  result;
949
950	/*
951	 * Not implemented.
952	 */
953
954	return (&result);
955}
956
957ypresponse *
958ypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
959{
960	static ypresponse  result;
961
962	/*
963	 * Not implemented.
964	 */
965
966	return (&result);
967}
968
969ypresponse *
970ypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
971{
972	static ypresponse  result;
973
974	/*
975	 * Not implemented.
976	 */
977
978	return (&result);
979}
980