1219888Sed/*
2257547Sray * Copyright (c) 1995
3219888Sed *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4219888Sed *
5219888Sed * Redistribution and use in source and binary forms, with or without
6219888Sed * modification, are permitted provided that the following conditions
7219888Sed * are met:
8257547Sray * 1. Redistributions of source code must retain the above copyright
9257547Sray *    notice, this list of conditions and the following disclaimer.
10257547Sray * 2. Redistributions in binary form must reproduce the above copyright
11219888Sed *    notice, this list of conditions and the following disclaimer in the
12219888Sed *    documentation and/or other materials provided with the distribution.
13219888Sed * 3. All advertising materials mentioning features or use of this software
14219888Sed *    must display the following acknowledgement:
15219888Sed *	This product includes software developed by Bill Paul.
16219888Sed * 4. Neither the name of the author nor the names of any co-contributors
17219888Sed *    may be used to endorse or promote products derived from this software
18219888Sed *    without specific prior written permission.
19219888Sed *
20219888Sed * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23219888Sed * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30219888Sed * SUCH DAMAGE.
31219888Sed *
32219888Sed */
33219888Sed
34219888Sed#include <sys/cdefs.h>
35219888Sed__FBSDID("$FreeBSD$");
36219888Sed
37219888Sed#include "yp.h"
38219888Sed#include "yp_extern.h"
39219888Sed#include <dirent.h>
40219888Sed#include <errno.h>
41219888Sed#include <stdlib.h>
42219888Sed#include <sys/stat.h>
43219888Sed#include <sys/param.h>
44219888Sed#include <sys/types.h>
45219888Sed#include <sys/socket.h>
46256145Sray#include <netinet/in.h>
47219888Sed#include <arpa/inet.h>
48219888Sed#include <rpc/rpc.h>
49219888Sed
50219888Sedint children = 0;
51219888Sed
52219888Sed#define	MASTER_STRING	"YP_MASTER_NAME"
53219888Sed#define	MASTER_SZ	sizeof(MASTER_STRING) - 1
54219888Sed#define	ORDER_STRING	"YP_LAST_MODIFIED"
55219888Sed#define	ORDER_SZ	sizeof(ORDER_STRING) - 1
56219888Sed
57219888Sedstatic pid_t
58219888Sedyp_fork(void)
59219888Sed{
60219888Sed	if (yp_pid != getpid()) {
61219888Sed		yp_error("child %d trying to fork!", getpid());
62219888Sed		errno = EEXIST;
63219888Sed		return(-1);
64219888Sed	}
65219888Sed
66219888Sed	return(fork());
67219888Sed}
68219888Sed
69219888Sed/*
70219888Sed * NIS v2 support. This is where most of the action happens.
71219888Sed */
72219888Sed
73219888Sedvoid *
74219888Sedypproc_null_2_svc(void *argp, struct svc_req *rqstp)
75219888Sed{
76219888Sed	static char * result;
77219888Sed	static char rval = 0;
78219888Sed
79219888Sed#ifdef DB_CACHE
80219888Sed	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
81219888Sed#else
82219888Sed	if (yp_access(NULL, (struct svc_req *)rqstp))
83219888Sed#endif
84219888Sed		return(NULL);
85257296Snwhitehorn
86219888Sed	result = &rval;
87219888Sed
88219888Sed	return((void *) &result);
89219888Sed}
90219888Sed
91219888Sedbool_t *
92257296Snwhitehornypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
93219888Sed{
94219888Sed	static bool_t  result;
95219888Sed
96219888Sed#ifdef DB_CACHE
97219888Sed	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
98219888Sed#else
99219888Sed	if (yp_access(NULL, (struct svc_req *)rqstp)) {
100219888Sed#endif
101219888Sed		result = FALSE;
102219888Sed		return (&result);
103219888Sed	}
104256145Sray
105256145Sray	if (argp == NULL || yp_validdomain(*argp))
106256145Sray		result = FALSE;
107256145Sray	else
108256145Sray		result = TRUE;
109256145Sray
110258023Sray	return (&result);
111256145Sray}
112219888Sed
113219888Sedbool_t *
114256145Srayypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
115219888Sed{
116219888Sed	static bool_t  result;
117219888Sed
118219888Sed#ifdef DB_CACHE
119219888Sed	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
120219888Sed#else
121219888Sed	if (yp_access(NULL, (struct svc_req *)rqstp))
122219888Sed#endif
123219888Sed		return (NULL);
124257986Sray
125219888Sed	if (argp == NULL || yp_validdomain(*argp))
126256145Sray		return (NULL);
127256145Sray	else
128256145Sray		result = TRUE;
129256145Sray
130256145Sray	return (&result);
131256145Sray}
132256145Sray
133256145Srayypresp_val *
134256145Srayypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
135219888Sed{
136256145Sray	static ypresp_val  result;
137256145Sray
138256145Sray	result.val.valdat_val = "";
139256145Sray	result.val.valdat_len = 0;
140256145Sray
141256145Sray#ifdef DB_CACHE
142256145Sray	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
143256145Sray#else
144256145Sray	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
145256145Sray#endif
146256145Sray		result.stat = YP_YPERR;
147256145Sray		return (&result);
148256145Sray	}
149256145Sray
150256145Sray	if (argp->domain == NULL || argp->map == NULL) {
151256145Sray		result.stat = YP_BADARGS;
152256145Sray		return (&result);
153256145Sray	}
154256145Sray
155256145Sray	if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) {
156256145Sray		result.stat = yp_errno;
157256145Sray		return(&result);
158256145Sray	}
159256145Sray
160256145Sray	result.stat = yp_getbykey(&argp->key, &result.val);
161256145Sray
162256145Sray	/*
163256145Sray	 * Do DNS lookups for hosts maps if database lookup failed.
164256145Sray	 */
165256145Sray
166256145Sray#ifdef DB_CACHE
167256145Sray	if (do_dns && result.stat != YP_TRUE &&
168256145Sray	    (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) ||
169256145Sray	    (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes")))) {
170256145Sray#else
171256145Sray	if (do_dns && result.stat != YP_TRUE &&
172256145Sray	    (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes"))) {
173256145Sray#endif
174256145Sray		char			nbuf[YPMAXRECORD];
175256145Sray
176256145Sray		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
177256145Sray		bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len);
178256145Sray		nbuf[argp->key.keydat_len] = '\0';
179256145Sray
180256145Sray		if (debug)
181256145Sray			yp_error("doing DNS lookup of %s", nbuf);
182256145Sray
183256145Sray		if (!strcmp(argp->map, "hosts.byname"))
184256145Sray			result.stat = yp_async_lookup_name(rqstp, nbuf,
185256145Sray			    AF_INET);
186256145Sray		else if (!strcmp(argp->map, "hosts.byaddr"))
187256145Sray			result.stat = yp_async_lookup_addr(rqstp, nbuf,
188256145Sray			    AF_INET);
189256145Sray		else if (!strcmp(argp->map, "ipnodes.byname"))
190256145Sray			result.stat = yp_async_lookup_name(rqstp, nbuf,
191256145Sray			    AF_INET6);
192256145Sray		else if (!strcmp(argp->map, "ipnodes.byaddr"))
193256145Sray			result.stat = yp_async_lookup_addr(rqstp, nbuf,
194256145Sray			    AF_INET6);
195256145Sray
196256145Sray		if (result.stat == YP_TRUE)
197256145Sray			return(NULL);
198256145Sray	}
199256145Sray
200256145Sray	return (&result);
201256145Sray}
202256145Sray
203256145Srayypresp_key_val *
204256145Srayypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
205256145Sray{
206256145Sray	static ypresp_key_val  result;
207256145Sray
208256145Sray	result.val.valdat_val = result.key.keydat_val = "";
209256145Sray	result.val.valdat_len = result.key.keydat_len = 0;
210256145Sray
211256145Sray#ifdef DB_CACHE
212256145Sray	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
213256145Sray#else
214256145Sray	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
215256145Sray#endif
216256145Sray		result.stat = YP_YPERR;
217256145Sray		return (&result);
218256145Sray	}
219256145Sray
220256145Sray	if (argp->domain == NULL) {
221219888Sed		result.stat = YP_BADARGS;
222219888Sed		return (&result);
223219888Sed	}
224256145Sray
225219888Sed	if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) {
226219888Sed		result.stat = yp_errno;
227219888Sed		return(&result);
228256145Sray	}
229256145Sray
230219888Sed	result.stat = yp_firstbykey(&result.key, &result.val);
231256145Sray
232219888Sed	return (&result);
233256145Sray}
234256145Sray
235256145Srayypresp_key_val *
236256145Srayypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
237256145Sray{
238219888Sed	static ypresp_key_val  result;
239219888Sed
240219888Sed	result.val.valdat_val = result.key.keydat_val = "";
241219888Sed	result.val.valdat_len = result.key.keydat_len = 0;
242219888Sed
243256145Sray#ifdef DB_CACHE
244256145Sray	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
245256145Sray#else
246219888Sed	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
247219888Sed#endif
248219888Sed		result.stat = YP_YPERR;
249256145Sray		return (&result);
250219888Sed	}
251256145Sray
252219888Sed	if (argp->domain == NULL || argp->map == NULL) {
253256145Sray		result.stat = YP_BADARGS;
254256145Sray		return (&result);
255256145Sray	}
256219888Sed
257219888Sed	if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) {
258219888Sed		result.stat = yp_errno;
259219888Sed		return(&result);
260219888Sed	}
261219888Sed
262219888Sed	result.key.keydat_len = argp->key.keydat_len;
263219888Sed	result.key.keydat_val = argp->key.keydat_val;
264219888Sed
265219888Sed	result.stat = yp_nextbykey(&result.key, &result.val);
266219888Sed
267219888Sed	return (&result);
268219888Sed}
269219888Sed
270219888Sedstatic void
271219888Sedypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid,
272219888Sed    unsigned int prognum, unsigned long port)
273219888Sed{
274219888Sed	CLIENT *clnt;
275219888Sed	int sock = RPC_ANYSOCK;
276219888Sed	struct timeval timeout;
277219888Sed	yppushresp_xfr ypxfr_resp;
278219888Sed	struct rpc_err err;
279219888Sed
280219888Sed	timeout.tv_sec = 5;
281219888Sed	timeout.tv_usec = 0;
282257076Sray	addr->sin_port = htons(port);
283257076Sray
284257076Sray	if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) {
285257076Sray		yp_error("%s: %s", inet_ntoa(addr->sin_addr),
286257076Sray		  clnt_spcreateerror("failed to establish callback handle"));
287257076Sray		return;
288257076Sray	}
289257076Sray
290257076Sray	ypxfr_resp.status = rval;
291257076Sray	ypxfr_resp.transid = transid;
292257076Sray
293257076Sray	/* Turn the timeout off -- we don't want to block. */
294257076Sray	timeout.tv_sec = 0;
295257076Sray	if (clnt_control(clnt, CLSET_TIMEOUT, &timeout) == FALSE)
296257076Sray		yp_error("failed to set timeout on ypproc_xfr callback");
297257076Sray
298257076Sray	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
299257076Sray		clnt_geterr(clnt, &err);
300257076Sray		if (err.re_status != RPC_SUCCESS &&
301257076Sray		    err.re_status != RPC_TIMEDOUT)
302257076Sray			yp_error("%s", clnt_sperror(clnt,
303257076Sray				"ypxfr callback failed"));
304257076Sray	}
305257076Sray
306257076Sray	clnt_destroy(clnt);
307219888Sed	return;
308257076Sray}
309257076Sray
310257076Sray#define YPXFR_RETURN(CODE) 						\
311257076Sray	/* Order is important: send regular RPC reply, then callback */	\
312257076Sray	result.xfrstat = CODE; 						\
313257076Sray	svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_ypresp_xfr, &result); \
314257076Sray	ypxfr_callback(CODE,rqhost,argp->transid, 			\
315257076Sray					argp->prog,argp->port); 	\
316257076Sray	return(NULL);
317257076Sray
318257076Srayypresp_xfr *
319257076Srayypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
320257076Sray{
321257076Sray	static ypresp_xfr  result;
322257076Sray	struct sockaddr_in *rqhost;
323257076Sray	ypresp_master *mres;
324257076Sray	ypreq_nokey mreq;
325257076Sray
326257076Sray	result.transid = argp->transid;
327257076Sray	rqhost = svc_getcaller(rqstp->rq_xprt);
328257076Sray
329257076Sray#ifdef DB_CACHE
330257076Sray	if (yp_access(argp->map_parms.map,
331257076Sray			argp->map_parms.domain, (struct svc_req *)rqstp)) {
332257076Sray#else
333257076Sray	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
334257076Sray#endif
335257076Sray		YPXFR_RETURN(YPXFR_REFUSED)
336257076Sray	}
337257076Sray
338257076Sray
339257076Sray	if (argp->map_parms.domain == NULL) {
340257076Sray		YPXFR_RETURN(YPXFR_BADARGS)
341257076Sray	}
342257076Sray
343257076Sray	if (yp_validdomain(argp->map_parms.domain)) {
344257076Sray		YPXFR_RETURN(YPXFR_NODOM)
345257076Sray	}
346257076Sray
347257076Sray	/*
348257076Sray	 * Determine the master host ourselves. The caller may
349257076Sray	 * be up to no good. This has the side effect of verifying
350257076Sray	 * that the requested map and domain actually exist.
351257076Sray	 */
352257076Sray
353257076Sray	mreq.domain = argp->map_parms.domain;
354257076Sray	mreq.map = argp->map_parms.map;
355257076Sray
356257076Sray	mres = ypproc_master_2_svc(&mreq, rqstp);
357257076Sray
358257076Sray	if (mres->stat != YP_TRUE) {
359257076Sray		yp_error("couldn't find master for map %s@%s",
360257076Sray						argp->map_parms.map,
361257076Sray						argp->map_parms.domain);
362257076Sray		yp_error("host at %s (%s) may be pulling my leg",
363257076Sray						argp->map_parms.peer,
364257076Sray						inet_ntoa(rqhost->sin_addr));
365257076Sray		YPXFR_RETURN(YPXFR_REFUSED)
366257076Sray	}
367257076Sray
368257076Sray	switch (yp_fork()) {
369257076Sray	case 0:
370257076Sray	{
371257076Sray		char g[11], t[11], p[11];
372257076Sray		char ypxfr_command[MAXPATHLEN + 2];
373257076Sray
374257076Sray		snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC);
375257076Sray		snprintf (t, sizeof(t), "%u", argp->transid);
376257076Sray		snprintf (g, sizeof(g), "%u", argp->prog);
377257076Sray		snprintf (p, sizeof(p), "%u", argp->port);
378257076Sray		if (debug) {
379257076Sray			close(0); close(1); close(2);
380257076Sray		}
381257076Sray		if (strcmp(yp_dir, _PATH_YP)) {
382257076Sray			execl(ypxfr_command, "ypxfr",
383257076Sray			"-d", argp->map_parms.domain,
384257076Sray		      	"-h", mres->peer,
385257076Sray			"-p", yp_dir, "-C", t,
386257076Sray		      	g, inet_ntoa(rqhost->sin_addr),
387257076Sray			p, argp->map_parms.map,
388257294Snwhitehorn		      	NULL);
389219888Sed		} else {
390219888Sed			execl(ypxfr_command, "ypxfr",
391257294Snwhitehorn			"-d", argp->map_parms.domain,
392219888Sed		      	"-h", mres->peer,
393219888Sed			"-C", t,
394219888Sed		      	g, inet_ntoa(rqhost->sin_addr),
395219888Sed			p, argp->map_parms.map,
396257076Sray		      	NULL);
397257076Sray		}
398257076Sray		yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
399257076Sray		YPXFR_RETURN(YPXFR_XFRERR)
400257076Sray		/*
401257076Sray		 * Just to safe, prevent PR #10970 from biting us in
402257076Sray		 * the unlikely case that execing ypxfr fails. We don't
403257076Sray		 * want to have any child processes spawned from this
404257076Sray		 * child process.
405219888Sed		 */
406219888Sed		_exit(0);
407219888Sed		break;
408219888Sed	}
409219888Sed	case -1:
410219888Sed		yp_error("ypxfr fork(): %s", strerror(errno));
411256145Sray		YPXFR_RETURN(YPXFR_XFRERR)
412219888Sed		break;
413219888Sed	default:
414219888Sed		result.xfrstat = YPXFR_SUCC;
415219888Sed		children++;
416219888Sed		break;
417219888Sed	}
418219888Sed
419219888Sed	return (&result);
420219888Sed}
421219888Sed#undef YPXFR_RETURN
422219888Sed
423256145Srayvoid *
424219888Sedypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
425219888Sed{
426219888Sed	static char * result;
427256145Sray	static char rval = 0;
428257076Sray
429219888Sed#ifdef DB_CACHE
430219888Sed	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
431219888Sed#else
432219888Sed	if (yp_access(NULL, (struct svc_req *)rqstp))
433219888Sed#endif
434219888Sed		return (NULL);
435219888Sed#ifdef DB_CACHE
436219888Sed	/* clear out the database cache */
437219888Sed	yp_flush_all();
438219888Sed#endif
439219888Sed	/* Re-read the securenets database for the hell of it. */
440219888Sed	load_securenets();
441219888Sed
442219888Sed	result = &rval;
443219888Sed	return((void *) &result);
444219888Sed}
445219888Sed
446219888Sed/*
447219888Sed * For ypproc_all, we have to send a stream of ypresp_all structures
448219888Sed * via TCP, but the XDR filter generated from the yp.x protocol
449219888Sed * definition file only serializes one such structure. This means that
450219888Sed * to send the whole stream, you need a wrapper which feeds all the
451219888Sed * records into the underlying XDR routine until it hits an 'EOF.'
452219888Sed * But to use the wrapper, you have to violate the boundaries between
453219888Sed * RPC layers by calling svc_sendreply() directly from the ypproc_all
454219888Sed * service routine instead of letting the RPC dispatcher do it.
455219888Sed *
456219888Sed * Bleah.
457219888Sed */
458219888Sed
459219888Sed/*
460219888Sed * Custom XDR routine for serialzing results of ypproc_all: keep
461219888Sed * reading from the database and spew until we run out of records
462219888Sed * or encounter an error.
463219888Sed */
464219888Sedstatic bool_t
465219888Sedxdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
466219888Sed{
467219888Sed	while (1) {
468219888Sed		/* Get a record. */
469219888Sed		if ((objp->ypresp_all_u.val.stat =
470219888Sed			yp_nextbykey(&objp->ypresp_all_u.val.key,
471219888Sed				     &objp->ypresp_all_u.val.val)) == YP_TRUE) {
472219888Sed			objp->more = TRUE;
473219888Sed		} else {
474219888Sed			objp->more = FALSE;
475256145Sray		}
476219888Sed
477219888Sed		/* Serialize. */
478219888Sed		if (!xdr_ypresp_all(xdrs, objp))
479219888Sed			return(FALSE);
480219888Sed		if (objp->more == FALSE)
481219888Sed			return(TRUE);
482219888Sed	}
483257294Snwhitehorn}
484257294Snwhitehorn
485257294Snwhitehornypresp_all *
486257294Snwhitehornypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
487257294Snwhitehorn{
488257294Snwhitehorn	static ypresp_all  result;
489257294Snwhitehorn
490257294Snwhitehorn	/*
491257294Snwhitehorn	 * Set this here so that the client will be forced to make
492257294Snwhitehorn	 * at least one attempt to read from us even if all we're
493257294Snwhitehorn	 * doing is returning an error.
494257294Snwhitehorn	 */
495257294Snwhitehorn	result.more = TRUE;
496257294Snwhitehorn	result.ypresp_all_u.val.key.keydat_len = 0;
497257294Snwhitehorn	result.ypresp_all_u.val.key.keydat_val = "";
498257294Snwhitehorn
499257294Snwhitehorn#ifdef DB_CACHE
500257294Snwhitehorn	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
501257294Snwhitehorn#else
502257294Snwhitehorn	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
503257294Snwhitehorn#endif
504257294Snwhitehorn		result.ypresp_all_u.val.stat = YP_YPERR;
505257294Snwhitehorn		return (&result);
506257294Snwhitehorn	}
507257294Snwhitehorn
508219888Sed	if (argp->domain == NULL || argp->map == NULL) {
509219888Sed		result.ypresp_all_u.val.stat = YP_BADARGS;
510219888Sed		return (&result);
511219888Sed	}
512219888Sed
513219888Sed	/*
514219888Sed	 * XXX If we hit the child limit, fail the request.
515219888Sed	 * If we don't, and the map is large, we could block for
516256145Sray	 * a long time in the parent.
517256145Sray	 */
518219888Sed	if (children >= MAX_CHILDREN) {
519256145Sray		result.ypresp_all_u.val.stat = YP_YPERR;
520219888Sed		return(&result);
521219888Sed	}
522219888Sed
523219888Sed	/*
524219888Sed	 * The ypproc_all procedure can take a while to complete.
525219888Sed	 * Best to handle it in a subprocess so the parent doesn't
526219888Sed	 * block. (Is there a better way to do this? Maybe with
527219888Sed	 * async socket I/O?)
528219888Sed	 */
529219888Sed	if (!debug) {
530219888Sed		switch (yp_fork()) {
531219888Sed		case 0:
532219888Sed			break;
533219888Sed		case -1:
534219888Sed			yp_error("ypall fork(): %s", strerror(errno));
535219888Sed			result.ypresp_all_u.val.stat = YP_YPERR;
536256145Sray			return(&result);
537256145Sray			break;
538219888Sed		default:
539219888Sed			children++;
540256145Sray			return (NULL);
541256145Sray			break;
542219888Sed		}
543219888Sed	}
544219888Sed
545219888Sed	/*
546219888Sed	 * Fix for PR #10971: don't let the child ypserv share
547219888Sed	 * DB handles with the parent process.
548219888Sed	 */
549219888Sed#ifdef DB_CACHE
550219888Sed	yp_flush_all();
551219888Sed#endif
552219888Sed
553219888Sed	if (yp_select_map(argp->map, argp->domain,
554219888Sed				&result.ypresp_all_u.val.key, 0) != YP_TRUE) {
555219888Sed		result.ypresp_all_u.val.stat = yp_errno;
556219888Sed		return(&result);
557219888Sed	}
558219888Sed
559219888Sed	/* Kick off the actual data transfer. */
560219888Sed	svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_my_ypresp_all, &result);
561219888Sed
562219888Sed	/*
563219888Sed	 * Proper fix for PR #10970: exit here so that we don't risk
564219888Sed	 * having a child spawned from this sub-process.
565219888Sed	 */
566219888Sed	if (!debug)
567219888Sed		_exit(0);
568219888Sed
569219888Sed	return &result;
570219888Sed}
571219888Sed
572219888Sedypresp_master *
573219888Sedypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
574256145Sray{
575219888Sed	static ypresp_master  result;
576219888Sed	static char ypvalbuf[YPMAXRECORD];
577219888Sed	keydat key = { MASTER_SZ, MASTER_STRING };
578219888Sed	valdat val;
579219888Sed
580219888Sed	result.peer = "";
581219888Sed
582219888Sed#ifdef DB_CACHE
583219888Sed	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
584219888Sed#else
585219888Sed	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
586219888Sed#endif
587219888Sed		result.stat = YP_YPERR;
588219888Sed		return(&result);
589219888Sed	}
590219888Sed
591219888Sed	if (argp->domain == NULL) {
592219888Sed		result.stat = YP_BADARGS;
593219888Sed		return (&result);
594219888Sed	}
595219888Sed
596219888Sed	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
597219888Sed		result.stat = yp_errno;
598219888Sed		return(&result);
599219888Sed	}
600219888Sed
601219888Sed	/*
602219888Sed	 * Note that we copy the data retrieved from the database to
603219888Sed	 * a private buffer and NUL terminate the buffer rather than
604219888Sed	 * terminating the data in place. We do this because by stuffing
605219888Sed	 * a '\0' into data.data, we will actually be corrupting memory
606219888Sed	 * allocated by the DB package. This is a bad thing now that we
607219888Sed	 * cache DB handles rather than closing the database immediately.
608219888Sed	 */
609219888Sed	result.stat = yp_getbykey(&key, &val);
610219888Sed	if (result.stat == YP_TRUE) {
611219888Sed		bcopy(val.valdat_val, &ypvalbuf, val.valdat_len);
612219888Sed		ypvalbuf[val.valdat_len] = '\0';
613219888Sed		result.peer = ypvalbuf;
614219888Sed	} else
615219888Sed		result.peer = "";
616219888Sed
617219888Sed	return (&result);
618219888Sed}
619219888Sed
620219888Sedypresp_order *
621219888Sedypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
622219888Sed{
623219888Sed	static ypresp_order  result;
624219888Sed	keydat key = { ORDER_SZ, ORDER_STRING };
625219888Sed	valdat val;
626219888Sed
627219888Sed	result.ordernum = 0;
628219888Sed
629219888Sed#ifdef DB_CACHE
630219888Sed	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
631219888Sed#else
632219888Sed	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
633219888Sed#endif
634219888Sed		result.stat = YP_YPERR;
635219888Sed		return(&result);
636219888Sed	}
637219888Sed
638219888Sed	if (argp->domain == NULL) {
639219888Sed		result.stat = YP_BADARGS;
640219888Sed		return (&result);
641257979Sray	}
642257979Sray
643219888Sed	/*
644257988Sray	 * We could just check the timestamp on the map file,
645219888Sed	 * but that's a hack: we'll only know the last time the file
646219888Sed	 * was touched, not the last time the database contents were
647219888Sed	 * updated.
648219888Sed	 */
649219888Sed
650219888Sed	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
651219888Sed		result.stat = yp_errno;
652219888Sed		return(&result);
653219888Sed	}
654219888Sed
655219888Sed	result.stat = yp_getbykey(&key, &val);
656219888Sed
657219888Sed	if (result.stat == YP_TRUE)
658257981Sray		result.ordernum = atoi(val.valdat_val);
659256145Sray	else
660257981Sray		result.ordernum = 0;
661257981Sray
662256145Sray	return (&result);
663257988Sray}
664219888Sed
665219888Sedstatic void yp_maplist_free(struct ypmaplist *yp_maplist)
666219888Sed{
667219888Sed	register struct ypmaplist *next;
668219888Sed
669219888Sed	while (yp_maplist) {
670219888Sed		next = yp_maplist->next;
671219888Sed		free(yp_maplist->map);
672256145Sray		free(yp_maplist);
673219888Sed		yp_maplist = next;
674219888Sed	}
675219888Sed	return;
676219888Sed}
677219888Sed
678219888Sedstatic struct ypmaplist *
679219888Sedyp_maplist_create(const char *domain)
680257981Sray{
681257981Sray	char yp_mapdir[MAXPATHLEN + 2];
682257981Sray	char yp_mapname[MAXPATHLEN + 2];
683219888Sed	struct ypmaplist *cur = NULL;
684257981Sray	struct ypmaplist *yp_maplist = NULL;
685257981Sray	DIR *dird;
686257981Sray	struct dirent *dirp;
687219888Sed	struct stat statbuf;
688219888Sed
689219888Sed	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
690256145Sray
691219888Sed	if ((dird = opendir(yp_mapdir)) == NULL) {
692219888Sed		yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno));
693219888Sed		return(NULL);
694219888Sed	}
695219888Sed
696256145Sray	while ((dirp = readdir(dird)) != NULL) {
697256903Sray		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
698219888Sed			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",
699219888Sed							yp_mapdir,dirp->d_name);
700257981Sray			if (stat(yp_mapname, &statbuf) < 0 ||
701257981Sray						!S_ISREG(statbuf.st_mode))
702257981Sray				continue;
703257981Sray			if ((cur = (struct ypmaplist *)
704257988Sray				malloc(sizeof(struct ypmaplist))) == NULL) {
705257981Sray				yp_error("malloc() failed");
706257981Sray				closedir(dird);
707257981Sray				yp_maplist_free(yp_maplist);
708257981Sray				return(NULL);
709257981Sray			}
710257981Sray			if ((cur->map = strdup(dirp->d_name)) == NULL) {
711257981Sray				yp_error("strdup() failed: %s",strerror(errno));
712257981Sray				closedir(dird);
713257988Sray				yp_maplist_free(yp_maplist);
714257981Sray				return(NULL);
715257981Sray			}
716257981Sray			cur->next = yp_maplist;
717257981Sray			yp_maplist = cur;
718257981Sray			if (debug)
719257981Sray				yp_error("map: %s", yp_maplist->map);
720257981Sray		}
721219888Sed
722219888Sed	}
723219888Sed	closedir(dird);
724219888Sed	return(yp_maplist);
725219888Sed}
726257387Sray
727219888Sedypresp_maplist *
728257387Srayypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
729257387Sray{
730219888Sed	static ypresp_maplist  result = { 0, NULL };
731257387Sray
732219888Sed#ifdef DB_CACHE
733219888Sed	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
734219888Sed#else
735219888Sed	if (yp_access(NULL, (struct svc_req *)rqstp)) {
736219888Sed#endif
737219888Sed		result.stat = YP_YPERR;
738219888Sed		return(&result);
739219888Sed	}
740219888Sed
741219888Sed	if (argp == NULL) {
742219888Sed		result.stat = YP_BADARGS;
743219888Sed		return (&result);
744219888Sed	}
745219888Sed
746257626Sray	if (yp_validdomain(*argp)) {
747257626Sray		result.stat = YP_NODOM;
748219888Sed		return (&result);
749219888Sed	}
750219888Sed
751219888Sed	/*
752219888Sed	 * We have to construct a linked list for the ypproc_maplist
753219888Sed	 * procedure using dynamically allocated memory. Since the XDR
754219888Sed	 * layer won't free this list for us, we have to deal with it
755219888Sed	 * ourselves. We call yp_maplist_free() first to free any
756219888Sed	 * previously allocated data we may have accumulated to insure
757256145Sray	 * that we have only one linked list in memory at any given
758256145Sray	 * time.
759256145Sray	 */
760256145Sray
761256145Sray	yp_maplist_free(result.maps);
762257722Sray
763256145Sray	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
764256145Sray		yp_error("yp_maplist_create failed");
765256145Sray		result.stat = YP_YPERR;
766256145Sray		return(&result);
767256145Sray	} else
768256145Sray		result.stat = YP_TRUE;
769257988Sray
770257988Sray	return (&result);
771256145Sray}
772256145Sray
773256145Sray/*
774256145Sray * NIS v1 support. The nullproc, domain and domain_nonack
775256145Sray * functions from v1 are identical to those in v2, so all
776256145Sray * we have to do is hand off to them.
777219888Sed *
778219888Sed * The other functions are mostly just wrappers around their v2
779219888Sed * counterparts. For example, for the v1 'match' procedure, we
780219888Sed * crack open the argument structure, make a request to the v2
781219888Sed * 'match' function, repackage the data into a v1 response and
782219888Sed * then send it on its way.
783256145Sray *
784256145Sray * Note that we don't support the pull, push and get procedures.
785256145Sray * There's little documentation available to show what they
786256145Sray * do, and I suspect they're meant largely for map transfers
787219888Sed * between master and slave servers.
788219888Sed */
789219888Sed
790219888Sedvoid *
791219888Sedypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
792219888Sed{
793230469Snwhitehorn	return(ypproc_null_2_svc(argp, rqstp));
794230469Snwhitehorn}
795230469Snwhitehorn
796219888Sedbool_t *
797256145Srayypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
798219888Sed{
799219888Sed	return(ypproc_domain_2_svc(argp, rqstp));
800219888Sed}
801219888Sed
802219888Sedbool_t *
803219888Sedypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
804219888Sed{
805219888Sed	return (ypproc_domain_nonack_2_svc(argp, rqstp));
806219888Sed}
807256145Sray
808219888Sed/*
809256145Sray * the 'match' procedure sends a response of type YPRESP_VAL
810256145Sray */
811219888Sedypresponse *
812219888Sedypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
813219888Sed{
814219888Sed	static ypresponse  result;
815219888Sed	ypresp_val *v2_result;
816219888Sed
817219888Sed	result.yp_resptype = YPRESP_VAL;
818219888Sed	result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
819257076Sray	result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
820219888Sed
821219888Sed	if (argp->yp_reqtype != YPREQ_KEY) {
822257076Sray		result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
823257076Sray		return(&result);
824257076Sray	}
825257076Sray
826219888Sed	v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
827219888Sed	if (v2_result == NULL)
828256145Sray		return(NULL);
829219888Sed
830256145Sray	bcopy(v2_result, &result.ypresponse_u.yp_resp_valtype,
831256145Sray	      sizeof(ypresp_val));
832219888Sed
833219888Sed	return (&result);
834219888Sed}
835219888Sed
836219888Sed/*
837219888Sed * the 'first' procedure sends a response of type YPRESP_KEY_VAL
838219888Sed */
839219888Sedypresponse *
840256145Srayypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
841256145Sray{
842256145Sray	static ypresponse  result;
843256145Sray	ypresp_key_val *v2_result;
844219888Sed
845219888Sed	result.yp_resptype = YPRESP_KEY_VAL;
846219888Sed	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
847219888Sed	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
848219888Sed	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
849219888Sed	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
850256145Sray
851257076Sray	if (argp->yp_reqtype != YPREQ_NOKEY) {
852257076Sray		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
853257076Sray		return(&result);
854257076Sray	}
855257076Sray
856257076Sray	v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
857219888Sed									rqstp);
858219888Sed	if (v2_result == NULL)
859219888Sed		return(NULL);
860257076Sray
861219888Sed	bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype,
862219888Sed	      sizeof(ypresp_key_val));
863219888Sed
864219888Sed	return (&result);
865256145Sray}
866219888Sed
867219888Sed/*
868257076Sray * the 'next' procedure sends a response of type YPRESP_KEY_VAL
869219888Sed */
870256145Srayypresponse *
871219888Sedypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
872219888Sed{
873257076Sray	static ypresponse  result;
874257076Sray	ypresp_key_val *v2_result;
875257076Sray
876219888Sed	result.yp_resptype = YPRESP_KEY_VAL;
877257076Sray	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
878257076Sray	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
879219888Sed	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
880257076Sray	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
881257076Sray
882219888Sed	if (argp->yp_reqtype != YPREQ_KEY) {
883257076Sray		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
884257076Sray		return(&result);
885219888Sed	}
886219888Sed
887219888Sed	v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
888219888Sed	if (v2_result == NULL)
889219888Sed		return(NULL);
890219888Sed
891219888Sed	bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype,
892219888Sed	      sizeof(ypresp_key_val));
893256145Sray
894257076Sray	return (&result);
895257076Sray}
896257076Sray
897257076Sray/*
898219888Sed * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
899219888Sed */
900219888Sedypresponse *
901219888Sedypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
902219888Sed{
903219888Sed	static ypresponse  result;
904219888Sed	ypresp_master *v2_result1;
905219888Sed	ypresp_order *v2_result2;
906219888Sed
907219888Sed	result.yp_resptype = YPRESP_MAP_PARMS;
908219888Sed	result.ypresponse_u.yp_resp_map_parmstype.domain =
909219888Sed		argp->yprequest_u.yp_req_nokeytype.domain;
910219888Sed	result.ypresponse_u.yp_resp_map_parmstype.map =
911256145Sray		argp->yprequest_u.yp_req_nokeytype.map;
912219888Sed	/*
913256145Sray	 * Hmm... there is no 'status' value in the
914256145Sray	 * yp_resp_map_parmstype structure, so I have to
915219888Sed	 * guess at what to do to indicate a failure.
916219888Sed	 * I hope this is right.
917219888Sed	 */
918219888Sed	result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
919219888Sed	result.ypresponse_u.yp_resp_map_parmstype.peer = "";
920219888Sed
921219888Sed	if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
922219888Sed		return(&result);
923219888Sed	}
924219888Sed
925219888Sed	v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
926219888Sed									rqstp);
927219888Sed	if (v2_result1 == NULL)
928219888Sed		return(NULL);
929219888Sed
930219888Sed	if (v2_result1->stat != YP_TRUE) {
931219888Sed		return(&result);
932219888Sed	}
933219888Sed
934219888Sed	v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
935219888Sed									rqstp);
936219888Sed	if (v2_result2 == NULL)
937219888Sed		return(NULL);
938219888Sed
939219888Sed	if (v2_result2->stat != YP_TRUE) {
940219888Sed		return(&result);
941219888Sed	}
942219888Sed
943219888Sed	result.ypresponse_u.yp_resp_map_parmstype.peer =
944219888Sed		v2_result1->peer;
945219888Sed	result.ypresponse_u.yp_resp_map_parmstype.ordernum =
946219888Sed		v2_result2->ordernum;
947219888Sed
948219888Sed	return (&result);
949219888Sed}
950219888Sed
951219888Sedypresponse *
952219888Sedypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
953219888Sed{
954219888Sed	static ypresponse  result;
955257978Sray
956257978Sray	/*
957257978Sray	 * Not implemented.
958219888Sed	 */
959219888Sed
960219888Sed	return (&result);
961256145Sray}
962256903Sray
963219888Sedypresponse *
964219888Sedypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
965219888Sed{
966219888Sed	static ypresponse  result;
967219888Sed
968219888Sed	/*
969219888Sed	 * Not implemented.
970219888Sed	 */
971219888Sed
972219888Sed	return (&result);
973219888Sed}
974219888Sed
975219888Sedypresponse *
976219888Sedypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
977219888Sed{
978219888Sed	static ypresponse  result;
979256145Sray
980256145Sray	/*
981256145Sray	 * Not implemented.
982256145Sray	 */
983256145Sray
984256145Sray	return (&result);
985256145Sray}
986256145Sray