yp_server.c revision 28042
1238106Sdes/*
2238106Sdes * Copyright (c) 1995
3238106Sdes *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4238106Sdes *
5238106Sdes * Redistribution and use in source and binary forms, with or without
6238106Sdes * modification, are permitted provided that the following conditions
7238106Sdes * are met:
8238106Sdes * 1. Redistributions of source code must retain the above copyright
9238106Sdes *    notice, this list of conditions and the following disclaimer.
10238106Sdes * 2. Redistributions in binary form must reproduce the above copyright
11238106Sdes *    notice, this list of conditions and the following disclaimer in the
12238106Sdes *    documentation and/or other materials provided with the distribution.
13238106Sdes * 3. All advertising materials mentioning features or use of this software
14238106Sdes *    must display the following acknowledgement:
15238106Sdes *	This product includes software developed by Bill Paul.
16238106Sdes * 4. Neither the name of the author nor the names of any co-contributors
17238106Sdes *    may be used to endorse or promote products derived from this software
18238106Sdes *    without specific prior written permission.
19238106Sdes *
20238106Sdes * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21238106Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22238106Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23238106Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24269257Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25269257Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26269257Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27269257Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28269257Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29269257Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30269257Sdes * SUCH DAMAGE.
31269257Sdes *
32269257Sdes */
33269257Sdes
34238106Sdes#include "yp.h"
35238106Sdes#include "yp_extern.h"
36238106Sdes#include <stdlib.h>
37238106Sdes#include <dirent.h>
38238106Sdes#include <sys/stat.h>
39238106Sdes#include <sys/param.h>
40238106Sdes#include <errno.h>
41238106Sdes#include <sys/types.h>
42238106Sdes#include <sys/socket.h>
43238106Sdes#include <netinet/in.h>
44238106Sdes#include <arpa/inet.h>
45238106Sdes#include <rpc/rpc.h>
46238106Sdes
47238106Sdes#ifndef lint
48238106Sdesstatic const char rcsid[] = "$Id: yp_server.c,v 1.22 1997/04/28 14:18:38 wpaul Exp $";
49238106Sdes#endif /* not lint */
50238106Sdes
51238106Sdesint forked = 0;
52238106Sdesint children = 0;
53238106Sdes
54238106Sdes#define	MASTER_STRING	"YP_MASTER_NAME"
55238106Sdes#define	MASTER_SZ	sizeof(MASTER_STRING) - 1
56238106Sdes#define	ORDER_STRING	"YP_LAST_MODIFIED"
57238106Sdes#define	ORDER_SZ	sizeof(ORDER_STRING) - 1
58238106Sdes
59238106Sdes/*
60238106Sdes * NIS v2 support. This is where most of the action happens.
61238106Sdes */
62238106Sdes
63238106Sdesvoid *
64238106Sdesypproc_null_2_svc(void *argp, struct svc_req *rqstp)
65238106Sdes{
66238106Sdes	static char * result;
67238106Sdes	static char rval = 0;
68238106Sdes
69238106Sdes#ifdef DB_CACHE
70238106Sdes	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
71238106Sdes#else
72238106Sdes	if (yp_access(NULL, (struct svc_req *)rqstp))
73238106Sdes#endif
74238106Sdes		return(NULL);
75238106Sdes
76238106Sdes	result = &rval;
77238106Sdes
78238106Sdes	return((void *) &result);
79238106Sdes}
80238106Sdes
81238106Sdesbool_t *
82238106Sdesypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
83238106Sdes{
84238106Sdes	static bool_t  result;
85238106Sdes
86238106Sdes#ifdef DB_CACHE
87238106Sdes	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
88238106Sdes#else
89238106Sdes	if (yp_access(NULL, (struct svc_req *)rqstp)) {
90238106Sdes#endif
91238106Sdes		result = FALSE;
92238106Sdes		return (&result);
93238106Sdes	}
94238106Sdes
95238106Sdes	if (argp == NULL || yp_validdomain(*argp))
96238106Sdes		result = FALSE;
97238106Sdes	else
98238106Sdes		result = TRUE;
99238106Sdes
100238106Sdes	return (&result);
101238106Sdes}
102238106Sdes
103238106Sdesbool_t *
104238106Sdesypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
105238106Sdes{
106238106Sdes	static bool_t  result;
107238106Sdes
108238106Sdes#ifdef DB_CACHE
109238106Sdes	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
110238106Sdes#else
111238106Sdes	if (yp_access(NULL, (struct svc_req *)rqstp))
112238106Sdes#endif
113238106Sdes		return (NULL);
114238106Sdes
115238106Sdes	if (argp == NULL || yp_validdomain(*argp))
116238106Sdes		return (NULL);
117238106Sdes	else
118238106Sdes		result = TRUE;
119238106Sdes
120238106Sdes	return (&result);
121238106Sdes}
122238106Sdes
123238106Sdesypresp_val *
124238106Sdesypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
125238106Sdes{
126238106Sdes	static ypresp_val  result;
127238106Sdes
128238106Sdes	result.val.valdat_val = "";
129238106Sdes	result.val.valdat_len = 0;
130238106Sdes
131238106Sdes#ifdef DB_CACHE
132238106Sdes	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
133238106Sdes#else
134238106Sdes	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
135238106Sdes#endif
136238106Sdes		result.stat = YP_YPERR;
137238106Sdes		return (&result);
138238106Sdes	}
139238106Sdes
140238106Sdes	if (argp->domain == NULL || argp->map == NULL) {
141238106Sdes		result.stat = YP_BADARGS;
142238106Sdes		return (&result);
143238106Sdes	}
144238106Sdes
145238106Sdes	if (yp_select_map(argp->map, argp->domain, &argp->key, 1) != YP_TRUE) {
146238106Sdes		result.stat = yp_errno;
147238106Sdes		return(&result);
148238106Sdes	}
149238106Sdes
150238106Sdes	result.stat = yp_getbykey(&argp->key, &result.val);
151238106Sdes
152238106Sdes	/*
153238106Sdes	 * Do DNS lookups for hosts maps if database lookup failed.
154238106Sdes	 */
155238106Sdes
156238106Sdes#ifdef DB_CACHE
157238106Sdes	if (result.stat != YP_TRUE &&
158238106Sdes	    (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) ||
159238106Sdes	    (strstr(argp->map, "hosts") && do_dns))) {
160238106Sdes#else
161238106Sdes	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
162238106Sdes#endif
163238106Sdes		char			nbuf[YPMAXRECORD];
164238106Sdes
165238106Sdes		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
166238106Sdes		bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len);
167238106Sdes		nbuf[argp->key.keydat_len] = '\0';
168238106Sdes
169238106Sdes		if (debug)
170238106Sdes			yp_error("Doing DNS lookup of %s", nbuf);
171238106Sdes
172238106Sdes		if (!strcmp(argp->map, "hosts.byname"))
173238106Sdes			result.stat = yp_async_lookup_name(rqstp, nbuf);
174238106Sdes		else if (!strcmp(argp->map, "hosts.byaddr"))
175238106Sdes			result.stat = yp_async_lookup_addr(rqstp, nbuf);
176238106Sdes
177238106Sdes		if (result.stat == YP_TRUE)
178238106Sdes			return(NULL);
179238106Sdes	}
180238106Sdes
181238106Sdes	return (&result);
182238106Sdes}
183238106Sdes
184238106Sdesypresp_key_val *
185238106Sdesypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
186238106Sdes{
187238106Sdes	static ypresp_key_val  result;
188238106Sdes
189238106Sdes	result.val.valdat_val = result.key.keydat_val = "";
190238106Sdes	result.val.valdat_len = result.key.keydat_len = 0;
191238106Sdes
192238106Sdes#ifdef DB_CACHE
193238106Sdes	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
194238106Sdes#else
195238106Sdes	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
196238106Sdes#endif
197238106Sdes		result.stat = YP_YPERR;
198238106Sdes		return (&result);
199238106Sdes	}
200238106Sdes
201238106Sdes	if (argp->domain == NULL) {
202238106Sdes		result.stat = YP_BADARGS;
203238106Sdes		return (&result);
204238106Sdes	}
205238106Sdes
206238106Sdes	if (yp_select_map(argp->map, argp->domain, &result.key, 0) != YP_TRUE) {
207238106Sdes		result.stat = yp_errno;
208238106Sdes		return(&result);
209238106Sdes	}
210238106Sdes
211238106Sdes	result.stat = yp_firstbykey(&result.key, &result.val);
212238106Sdes
213238106Sdes	return (&result);
214238106Sdes}
215238106Sdes
216238106Sdesypresp_key_val *
217238106Sdesypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
218238106Sdes{
219238106Sdes	static ypresp_key_val  result;
220
221	result.val.valdat_val = result.key.keydat_val = "";
222	result.val.valdat_len = result.key.keydat_len = 0;
223
224#ifdef DB_CACHE
225	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
226#else
227	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
228#endif
229		result.stat = YP_YPERR;
230		return (&result);
231	}
232
233	if (argp->domain == NULL || argp->map == NULL) {
234		result.stat = YP_BADARGS;
235		return (&result);
236	}
237
238	if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) {
239		result.stat = yp_errno;
240		return(&result);
241	}
242
243	result.key.keydat_len = argp->key.keydat_len;
244	result.key.keydat_val = argp->key.keydat_val;
245
246	result.stat = yp_nextbykey(&result.key, &result.val);
247
248	return (&result);
249}
250
251static void ypxfr_callback(rval,addr,transid,prognum,port)
252	ypxfrstat rval;
253	struct sockaddr_in *addr;
254	unsigned int transid;
255	unsigned int prognum;
256	unsigned long port;
257{
258	CLIENT *clnt;
259	int sock = RPC_ANYSOCK;
260	struct timeval timeout;
261	yppushresp_xfr ypxfr_resp;
262	struct rpc_err err;
263
264	timeout.tv_sec = 5;
265	timeout.tv_usec = 0;
266	addr->sin_port = htons(port);
267
268	if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) {
269		yp_error("%s: %s", inet_ntoa(addr->sin_addr),
270		  clnt_spcreateerror("failed to establish callback handle"));
271		return;
272	}
273
274	ypxfr_resp.status = rval;
275	ypxfr_resp.transid = transid;
276
277	/* Turn the timeout off -- we don't want to block. */
278	timeout.tv_sec = 0;
279	if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE)
280		yp_error("failed to set timeout on ypproc_xfr callback");
281
282	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
283		clnt_geterr(clnt, &err);
284		if (err.re_status != RPC_SUCCESS &&
285		    err.re_status != RPC_TIMEDOUT)
286			yp_error("%s", clnt_sperror(clnt,
287				"ypxfr callback failed"));
288	}
289
290	clnt_destroy(clnt);
291	return;
292}
293
294#define YPXFR_RETURN(CODE) 						\
295	/* Order is important: send regular RPC reply, then callback */	\
296	result.xfrstat = CODE; 						\
297	svc_sendreply(rqstp->rq_xprt, xdr_ypresp_xfr, (char *)&result); \
298	ypxfr_callback(CODE,rqhost,argp->transid, 			\
299					argp->prog,argp->port); 	\
300	return(NULL);
301
302ypresp_xfr *
303ypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
304{
305	static ypresp_xfr  result;
306	struct sockaddr_in *rqhost;
307	ypresp_master *mres;
308	ypreq_nokey mreq;
309
310	result.transid = argp->transid;
311	rqhost = svc_getcaller(rqstp->rq_xprt);
312
313#ifdef DB_CACHE
314	if (yp_access(argp->map_parms.map,
315			argp->map_parms.domain, (struct svc_req *)rqstp)) {
316#else
317	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
318#endif
319		YPXFR_RETURN(YPXFR_REFUSED)
320	}
321
322
323	if (argp->map_parms.domain == NULL) {
324		YPXFR_RETURN(YPXFR_BADARGS)
325	}
326
327	if (yp_validdomain(argp->map_parms.domain)) {
328		YPXFR_RETURN(YPXFR_NODOM)
329	}
330
331	/*
332	 * Determine the master host ourselves. The caller may
333	 * be up to no good. This has the side effect of verifying
334	 * that the requested map and domain actually exist.
335	 */
336
337	mreq.domain = argp->map_parms.domain;
338	mreq.map = argp->map_parms.map;
339
340	mres = ypproc_master_2_svc(&mreq, rqstp);
341
342	if (mres->stat != YP_TRUE) {
343		yp_error("couldn't find master for map %s@%s",
344						argp->map_parms.map,
345						argp->map_parms.domain);
346		yp_error("host at %s (%s) may be pulling my leg",
347						argp->map_parms.peer,
348						inet_ntoa(rqhost->sin_addr));
349		YPXFR_RETURN(YPXFR_REFUSED)
350	}
351
352	switch(fork()) {
353	case 0:
354	{
355		char g[11], t[11], p[11];
356		char ypxfr_command[MAXPATHLEN + 2];
357
358		sprintf (ypxfr_command, "%sypxfr", _PATH_LIBEXEC);
359		sprintf (t, "%u", argp->transid);
360		sprintf (g, "%u", argp->prog);
361		sprintf (p, "%u", argp->port);
362		if (debug) {
363			close(0); close(1); close(2);
364		}
365		if (strcmp(yp_dir, _PATH_YP)) {
366			execl(ypxfr_command, "ypxfr",
367			"-d", argp->map_parms.domain,
368		      	"-h", mres->peer,
369			"-p", yp_dir, "-C", t,
370		      	g, inet_ntoa(rqhost->sin_addr),
371			p, argp->map_parms.map,
372		      	NULL);
373		} else {
374			execl(ypxfr_command, "ypxfr",
375			"-d", argp->map_parms.domain,
376		      	"-h", mres->peer,
377			"-C", t,
378		      	g, inet_ntoa(rqhost->sin_addr),
379			p, argp->map_parms.map,
380		      	NULL);
381		}
382		forked++;
383		yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
384		YPXFR_RETURN(YPXFR_XFRERR)
385		break;
386	}
387	case -1:
388		yp_error("ypxfr fork(): %s", strerror(errno));
389		YPXFR_RETURN(YPXFR_XFRERR)
390		break;
391	default:
392		result.xfrstat = YPXFR_SUCC;
393		children++;
394		forked = 0;
395		break;
396	}
397
398	return (&result);
399}
400#undef YPXFR_RETURN
401
402void *
403ypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
404{
405	static char * result;
406	static char rval = 0;
407
408#ifdef DB_CACHE
409	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
410#else
411	if (yp_access(NULL, (struct svc_req *)rqstp))
412#endif
413		return (NULL);
414#ifdef DB_CACHE
415	/* clear out the database cache */
416	yp_flush_all();
417#endif
418	/* Re-read the securenets database for the hell of it. */
419	load_securenets();
420
421	result = &rval;
422	return((void *) &result);
423}
424
425/*
426 * For ypproc_all, we have to send a stream of ypresp_all structures
427 * via TCP, but the XDR filter generated from the yp.x protocol
428 * definition file only serializes one such structure. This means that
429 * to send the whole stream, you need a wrapper which feeds all the
430 * records into the underlying XDR routine until it hits an 'EOF.'
431 * But to use the wrapper, you have to violate the boundaries between
432 * RPC layers by calling svc_sendreply() directly from the ypproc_all
433 * service routine instead of letting the RPC dispatcher do it.
434 *
435 * Bleah.
436 */
437
438/*
439 * Custom XDR routine for serialzing results of ypproc_all: keep
440 * reading from the database and spew until we run out of records
441 * or encounter an error.
442 */
443static bool_t
444xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
445{
446	while (1) {
447		/* Get a record. */
448		if ((objp->ypresp_all_u.val.stat =
449			yp_nextbykey(&objp->ypresp_all_u.val.key,
450				     &objp->ypresp_all_u.val.val)) == YP_TRUE) {
451			objp->more = TRUE;
452		} else {
453			objp->more = FALSE;
454		}
455
456		/* Serialize. */
457		if (!xdr_ypresp_all(xdrs, objp))
458			return(FALSE);
459		if (objp->more == FALSE)
460			return(TRUE);
461	}
462}
463
464ypresp_all *
465ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
466{
467	static ypresp_all  result;
468
469	/*
470	 * Set this here so that the client will be forced to make
471	 * at least one attempt to read from us even if all we're
472	 * doing is returning an error.
473	 */
474	result.more = TRUE;
475	result.ypresp_all_u.val.key.keydat_len = 0;
476	result.ypresp_all_u.val.key.keydat_val = "";
477
478#ifdef DB_CACHE
479	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
480#else
481	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
482#endif
483		result.ypresp_all_u.val.stat = YP_YPERR;
484		return (&result);
485	}
486
487	if (argp->domain == NULL || argp->map == NULL) {
488		result.ypresp_all_u.val.stat = YP_BADARGS;
489		return (&result);
490	}
491
492	/*
493	 * XXX If we hit the child limit, fail the request.
494	 * If we don't, and the map is large, we could block for
495	 * a long time in the parent.
496	 */
497	if (children >= MAX_CHILDREN) {
498		result.ypresp_all_u.val.stat = YP_YPERR;
499		return(&result);
500	}
501
502	/*
503	 * The ypproc_all procedure can take a while to complete.
504	 * Best to handle it in a subprocess so the parent doesn't
505	 * block. (Is there a better way to do this? Maybe with
506	 * async socket I/O?)
507	 */
508	if (!debug && children < MAX_CHILDREN && fork()) {
509		children++;
510		forked = 0;
511		return (NULL);
512	} else {
513		forked++;
514	}
515
516	if (yp_select_map(argp->map, argp->domain,
517				&result.ypresp_all_u.val.key, 0) != YP_TRUE) {
518		result.ypresp_all_u.val.stat = yp_errno;
519		return(&result);
520	}
521
522	/* Kick off the actual data transfer. */
523	svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result);
524
525	/*
526	 * Returning NULL prevents the dispatcher from calling
527	 * svc_sendreply() since we already did it.
528	 */
529	return (NULL);
530}
531
532ypresp_master *
533ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
534{
535	static ypresp_master  result;
536	static char ypvalbuf[YPMAXRECORD];
537	keydat key = { MASTER_SZ, MASTER_STRING };
538	valdat val;
539
540	result.peer = "";
541
542#ifdef DB_CACHE
543	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
544#else
545	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
546#endif
547		result.stat = YP_YPERR;
548		return(&result);
549	}
550
551	if (argp->domain == NULL) {
552		result.stat = YP_BADARGS;
553		return (&result);
554	}
555
556	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
557		result.stat = yp_errno;
558		return(&result);
559	}
560
561	/*
562	 * Note that we copy the data retrieved from the database to
563	 * a private buffer and NUL terminate the buffer rather than
564	 * terminating the data in place. We do this because by stuffing
565	 * a '\0' into data.data, we will actually be corrupting memory
566	 * allocated by the DB package. This is a bad thing now that we
567	 * cache DB handles rather than closing the database immediately.
568	 */
569	result.stat = yp_getbykey(&key, &val);
570	if (result.stat == YP_TRUE) {
571		bcopy((char *)val.valdat_val, (char *)&ypvalbuf,
572						val.valdat_len);
573		ypvalbuf[val.valdat_len] = '\0';
574		result.peer = (char *)&ypvalbuf;
575	} else
576		result.peer = "";
577
578	return (&result);
579}
580
581ypresp_order *
582ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
583{
584	static ypresp_order  result;
585	keydat key = { ORDER_SZ, ORDER_STRING };
586	valdat val;
587
588	result.ordernum = 0;
589
590#ifdef DB_CACHE
591	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
592#else
593	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
594#endif
595		result.stat = YP_YPERR;
596		return(&result);
597	}
598
599	if (argp->domain == NULL) {
600		result.stat = YP_BADARGS;
601		return (&result);
602	}
603
604	/*
605	 * We could just check the timestamp on the map file,
606	 * but that's a hack: we'll only know the last time the file
607	 * was touched, not the last time the database contents were
608	 * updated.
609	 */
610
611	if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
612		result.stat = yp_errno;
613		return(&result);
614	}
615
616	result.stat = yp_getbykey(&key, &val);
617
618	if (result.stat == YP_TRUE)
619		result.ordernum = atoi((char *)val.valdat_val);
620	else
621		result.ordernum = 0;
622
623	return (&result);
624}
625
626static void yp_maplist_free(yp_maplist)
627	struct ypmaplist *yp_maplist;
628{
629	register struct ypmaplist *next;
630
631	while(yp_maplist) {
632		next = yp_maplist->next;
633		free(yp_maplist->map);
634		free(yp_maplist);
635		yp_maplist = next;
636	}
637	return;
638}
639
640static struct ypmaplist *yp_maplist_create(domain)
641	const char *domain;
642{
643	char yp_mapdir[MAXPATHLEN + 2];
644	char yp_mapname[MAXPATHLEN + 2];
645	struct ypmaplist *cur = NULL;
646	struct ypmaplist *yp_maplist = NULL;
647	DIR *dird;
648	struct dirent *dirp;
649	struct stat statbuf;
650
651	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
652
653	if ((dird = opendir(yp_mapdir)) == NULL) {
654		yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno));
655		return(NULL);
656	}
657
658	while ((dirp = readdir(dird)) != NULL) {
659		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
660			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",
661							yp_mapdir,dirp->d_name);
662			if (stat(yp_mapname, &statbuf) < 0 ||
663						!S_ISREG(statbuf.st_mode))
664				continue;
665			if ((cur = (struct ypmaplist *)
666				malloc(sizeof(struct ypmaplist))) == NULL) {
667				yp_error("malloc() failed: %s",strerror(errno));
668				closedir(dird);
669				yp_maplist_free(yp_maplist);
670				return(NULL);
671			}
672			if ((cur->map = (char *)strdup(dirp->d_name)) == NULL) {
673				yp_error("strdup() failed: %s",strerror(errno));
674				closedir(dird);
675				yp_maplist_free(yp_maplist);
676				return(NULL);
677			}
678			cur->next = yp_maplist;
679			yp_maplist = cur;
680			if (debug)
681				yp_error("map: %s", yp_maplist->map);
682		}
683
684	}
685	closedir(dird);
686	return(yp_maplist);
687}
688
689ypresp_maplist *
690ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
691{
692	static ypresp_maplist  result = { 0, NULL };
693
694#ifdef DB_CACHE
695	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
696#else
697	if (yp_access(NULL, (struct svc_req *)rqstp)) {
698#endif
699		result.stat = YP_YPERR;
700		return(&result);
701	}
702
703	if (argp == NULL) {
704		result.stat = YP_BADARGS;
705		return (&result);
706	}
707
708	if (yp_validdomain(*argp)) {
709		result.stat = YP_NODOM;
710		return (&result);
711	}
712
713	/*
714	 * We have to construct a linked list for the ypproc_maplist
715	 * procedure using dynamically allocated memory. Since the XDR
716	 * layer won't free this list for us, we have to deal with it
717	 * ourselves. We call yp_maplist_free() first to free any
718	 * previously allocated data we may have accumulated to insure
719	 * that we have only one linked list in memory at any given
720	 * time.
721	 */
722
723	yp_maplist_free(result.maps);
724
725	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
726		yp_error("yp_maplist_create failed");
727		result.stat = YP_YPERR;
728		return(&result);
729	} else
730		result.stat = YP_TRUE;
731
732	return (&result);
733}
734
735/*
736 * NIS v1 support. The nullproc, domain and domain_nonack
737 * functions from v1 are identical to those in v2, so all
738 * we have to do is hand off to them.
739 *
740 * The other functions are mostly just wrappers around their v2
741 * counterparts. For example, for the v1 'match' procedure, we
742 * crack open the argument structure, make a request to the v2
743 * 'match' function, repackage the data into a v1 response and
744 * then send it on its way.
745 *
746 * Note that we don't support the pull, push and get procedures.
747 * There's little documentation available to show what they
748 * do, and I suspect they're meant largely for map transfers
749 * between master and slave servers.
750 */
751
752void *
753ypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
754{
755	return(ypproc_null_2_svc(argp, rqstp));
756}
757
758bool_t *
759ypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
760{
761	return(ypproc_domain_2_svc(argp, rqstp));
762}
763
764bool_t *
765ypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
766{
767	return (ypproc_domain_nonack_2_svc(argp, rqstp));
768}
769
770/*
771 * the 'match' procedure sends a response of type YPRESP_VAL
772 */
773ypresponse *
774ypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
775{
776	static ypresponse  result;
777	ypresp_val *v2_result;
778
779	result.yp_resptype = YPRESP_VAL;
780	result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
781	result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
782
783	if (argp->yp_reqtype != YPREQ_KEY) {
784		result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
785		return(&result);
786	}
787
788	v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
789	if (v2_result == NULL)
790		return(NULL);
791
792	bcopy((char *)v2_result,
793	      (char *)&result.ypresponse_u.yp_resp_valtype,
794	      sizeof(ypresp_val));
795
796	return (&result);
797}
798
799/*
800 * the 'first' procedure sends a response of type YPRESP_KEY_VAL
801 */
802ypresponse *
803ypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
804{
805	static ypresponse  result;
806	ypresp_key_val *v2_result;
807
808	result.yp_resptype = YPRESP_KEY_VAL;
809	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
810	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
811	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
812	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
813
814	if (argp->yp_reqtype != YPREQ_NOKEY) {
815		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
816		return(&result);
817	}
818
819	v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
820									rqstp);
821	if (v2_result == NULL)
822		return(NULL);
823
824	bcopy((char *)v2_result,
825	      (char *)&result.ypresponse_u.yp_resp_key_valtype,
826	      sizeof(ypresp_key_val));
827
828	return (&result);
829}
830
831/*
832 * the 'next' procedure sends a response of type YPRESP_KEY_VAL
833 */
834ypresponse *
835ypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
836{
837	static ypresponse  result;
838	ypresp_key_val *v2_result;
839
840	result.yp_resptype = YPRESP_KEY_VAL;
841	result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
842	result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
843	result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
844	result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
845
846	if (argp->yp_reqtype != YPREQ_KEY) {
847		result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
848		return(&result);
849	}
850
851	v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
852	if (v2_result == NULL)
853		return(NULL);
854
855	bcopy((char *)v2_result,
856	      (char *)&result.ypresponse_u.yp_resp_key_valtype,
857	      sizeof(ypresp_key_val));
858
859	return (&result);
860}
861
862/*
863 * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
864 */
865ypresponse *
866ypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
867{
868	static ypresponse  result;
869	ypresp_master *v2_result1;
870	ypresp_order *v2_result2;
871
872	result.yp_resptype = YPRESP_MAP_PARMS;
873	result.ypresponse_u.yp_resp_map_parmstype.domain =
874		argp->yprequest_u.yp_req_nokeytype.domain;
875	result.ypresponse_u.yp_resp_map_parmstype.map =
876		argp->yprequest_u.yp_req_nokeytype.map;
877	/*
878	 * Hmm... there is no 'status' value in the
879	 * yp_resp_map_parmstype structure, so I have to
880	 * guess at what to do to indicate a failure.
881	 * I hope this is right.
882	 */
883	result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
884	result.ypresponse_u.yp_resp_map_parmstype.peer = "";
885
886	if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
887		return(&result);
888	}
889
890	v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
891									rqstp);
892	if (v2_result1 == NULL)
893		return(NULL);
894
895	if (v2_result1->stat != YP_TRUE) {
896		return(&result);
897	}
898
899	v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
900									rqstp);
901	if (v2_result2 == NULL)
902		return(NULL);
903
904	if (v2_result2->stat != YP_TRUE) {
905		return(&result);
906	}
907
908	result.ypresponse_u.yp_resp_map_parmstype.peer =
909		v2_result1->peer;
910	result.ypresponse_u.yp_resp_map_parmstype.ordernum =
911		v2_result2->ordernum;
912
913	return (&result);
914}
915
916ypresponse *
917ypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
918{
919	static ypresponse  result;
920
921	/*
922	 * Not implemented.
923	 */
924
925	return (&result);
926}
927
928ypresponse *
929ypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
930{
931	static ypresponse  result;
932
933	/*
934	 * Not implemented.
935	 */
936
937	return (&result);
938}
939
940ypresponse *
941ypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
942{
943	static ypresponse  result;
944
945	/*
946	 * Not implemented.
947	 */
948
949	return (&result);
950}
951