yp_server.c revision 90298
1/*
2 * Copyright (c) 1995
3 *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34#ifndef lint
35static const char rcsid[] =
36  "$FreeBSD: head/usr.sbin/ypserv/yp_server.c 90298 2002-02-06 15:26:07Z des $";
37#endif /* not lint */
38
39#include "yp.h"
40#include "yp_extern.h"
41#include <dirent.h>
42#include <errno.h>
43#include <stdlib.h>
44#include <sys/stat.h>
45#include <sys/param.h>
46#include <sys/types.h>
47#include <sys/socket.h>
48#include <netinet/in.h>
49#include <arpa/inet.h>
50#include <rpc/rpc.h>
51
52int children = 0;
53
54#define	MASTER_STRING	"YP_MASTER_NAME"
55#define	MASTER_SZ	sizeof(MASTER_STRING) - 1
56#define	ORDER_STRING	"YP_LAST_MODIFIED"
57#define	ORDER_SZ	sizeof(ORDER_STRING) - 1
58
59static pid_t
60yp_fork(void)
61{
62	if (yp_pid != getpid()) {
63		yp_error("child %d trying to fork!", getpid());
64		errno = EEXIST;
65		return(-1);
66	}
67
68	return(fork());
69}
70
71/*
72 * NIS v2 support. This is where most of the action happens.
73 */
74
75void *
76ypproc_null_2_svc(void *argp, struct svc_req *rqstp)
77{
78	static char * result;
79	static char rval = 0;
80
81#ifdef DB_CACHE
82	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
83#else
84	if (yp_access(NULL, (struct svc_req *)rqstp))
85#endif
86		return(NULL);
87
88	result = &rval;
89
90	return((void *) &result);
91}
92
93bool_t *
94ypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
95{
96	static bool_t  result;
97
98#ifdef DB_CACHE
99	if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
100#else
101	if (yp_access(NULL, (struct svc_req *)rqstp)) {
102#endif
103		result = FALSE;
104		return (&result);
105	}
106
107	if (argp == NULL || yp_validdomain(*argp))
108		result = FALSE;
109	else
110		result = TRUE;
111
112	return (&result);
113}
114
115bool_t *
116ypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
117{
118	static bool_t  result;
119
120#ifdef DB_CACHE
121	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
122#else
123	if (yp_access(NULL, (struct svc_req *)rqstp))
124#endif
125		return (NULL);
126
127	if (argp == NULL || yp_validdomain(*argp))
128		return (NULL);
129	else
130		result = TRUE;
131
132	return (&result);
133}
134
135ypresp_val *
136ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
137{
138	static ypresp_val  result;
139
140	result.val.valdat_val = "";
141	result.val.valdat_len = 0;
142
143#ifdef DB_CACHE
144	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
145#else
146	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
147#endif
148		result.stat = YP_YPERR;
149		return (&result);
150	}
151
152	if (argp->domain == NULL || argp->map == NULL) {
153		result.stat = YP_BADARGS;
154		return (&result);
155	}
156
157	if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) {
158		result.stat = yp_errno;
159		return(&result);
160	}
161
162	result.stat = yp_getbykey(&argp->key, &result.val);
163
164	/*
165	 * Do DNS lookups for hosts maps if database lookup failed.
166	 */
167
168#ifdef DB_CACHE
169	if (result.stat != YP_TRUE &&
170	    (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) ||
171	    (strstr(argp->map, "hosts") && do_dns))) {
172#else
173	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
174#endif
175		char			nbuf[YPMAXRECORD];
176
177		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
178		bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len);
179		nbuf[argp->key.keydat_len] = '\0';
180
181		if (debug)
182			yp_error("doing DNS lookup of %s", nbuf);
183
184		if (!strcmp(argp->map, "hosts.byname"))
185			result.stat = yp_async_lookup_name(rqstp, nbuf);
186		else if (!strcmp(argp->map, "hosts.byaddr"))
187			result.stat = yp_async_lookup_addr(rqstp, nbuf);
188
189		if (result.stat == YP_TRUE)
190			return(NULL);
191	}
192
193	return (&result);
194}
195
196ypresp_key_val *
197ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
198{
199	static ypresp_key_val  result;
200
201	result.val.valdat_val = result.key.keydat_val = "";
202	result.val.valdat_len = result.key.keydat_len = 0;
203
204#ifdef DB_CACHE
205	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
206#else
207	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
208#endif
209		result.stat = YP_YPERR;
210		return (&result);
211	}
212
213	if (argp->domain == NULL) {
214		result.stat = YP_BADARGS;
215		return (&result);
216	}
217
218	if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) {
219		result.stat = yp_errno;
220		return(&result);
221	}
222
223	result.stat = yp_firstbykey(&result.key, &result.val);
224
225	return (&result);
226}
227
228ypresp_key_val *
229ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
230{
231	static ypresp_key_val  result;
232
233	result.val.valdat_val = result.key.keydat_val = "";
234	result.val.valdat_len = result.key.keydat_len = 0;
235
236#ifdef DB_CACHE
237	if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
238#else
239	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
240#endif
241		result.stat = YP_YPERR;
242		return (&result);
243	}
244
245	if (argp->domain == NULL || argp->map == NULL) {
246		result.stat = YP_BADARGS;
247		return (&result);
248	}
249
250	if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) {
251		result.stat = yp_errno;
252		return(&result);
253	}
254
255	result.key.keydat_len = argp->key.keydat_len;
256	result.key.keydat_val = argp->key.keydat_val;
257
258	result.stat = yp_nextbykey(&result.key, &result.val);
259
260	return (&result);
261}
262
263static void
264ypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid,
265    unsigned int prognum, unsigned long port)
266{
267	CLIENT *clnt;
268	int sock = RPC_ANYSOCK;
269	struct timeval timeout;
270	yppushresp_xfr ypxfr_resp;
271	struct rpc_err err;
272
273	timeout.tv_sec = 5;
274	timeout.tv_usec = 0;
275	addr->sin_port = htons(port);
276
277	if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) {
278		yp_error("%s: %s", inet_ntoa(addr->sin_addr),
279		  clnt_spcreateerror("failed to establish callback handle"));
280		return;
281	}
282
283	ypxfr_resp.status = rval;
284	ypxfr_resp.transid = transid;
285
286	/* Turn the timeout off -- we don't want to block. */
287	timeout.tv_sec = 0;
288	if (clnt_control(clnt, CLSET_TIMEOUT, (char *)&timeout) == FALSE)
289		yp_error("failed to set timeout on ypproc_xfr callback");
290
291	if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
292		clnt_geterr(clnt, &err);
293		if (err.re_status != RPC_SUCCESS &&
294		    err.re_status != RPC_TIMEDOUT)
295			yp_error("%s", clnt_sperror(clnt,
296				"ypxfr callback failed"));
297	}
298
299	clnt_destroy(clnt);
300	return;
301}
302
303#define YPXFR_RETURN(CODE) 						\
304	/* Order is important: send regular RPC reply, then callback */	\
305	result.xfrstat = CODE; 						\
306	svc_sendreply(rqstp->rq_xprt, xdr_ypresp_xfr, (char *)&result); \
307	ypxfr_callback(CODE,rqhost,argp->transid, 			\
308					argp->prog,argp->port); 	\
309	return(NULL);
310
311ypresp_xfr *
312ypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
313{
314	static ypresp_xfr  result;
315	struct sockaddr_in *rqhost;
316	ypresp_master *mres;
317	ypreq_nokey mreq;
318
319	result.transid = argp->transid;
320	rqhost = svc_getcaller(rqstp->rq_xprt);
321
322#ifdef DB_CACHE
323	if (yp_access(argp->map_parms.map,
324			argp->map_parms.domain, (struct svc_req *)rqstp)) {
325#else
326	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
327#endif
328		YPXFR_RETURN(YPXFR_REFUSED)
329	}
330
331
332	if (argp->map_parms.domain == NULL) {
333		YPXFR_RETURN(YPXFR_BADARGS)
334	}
335
336	if (yp_validdomain(argp->map_parms.domain)) {
337		YPXFR_RETURN(YPXFR_NODOM)
338	}
339
340	/*
341	 * Determine the master host ourselves. The caller may
342	 * be up to no good. This has the side effect of verifying
343	 * that the requested map and domain actually exist.
344	 */
345
346	mreq.domain = argp->map_parms.domain;
347	mreq.map = argp->map_parms.map;
348
349	mres = ypproc_master_2_svc(&mreq, rqstp);
350
351	if (mres->stat != YP_TRUE) {
352		yp_error("couldn't find master for map %s@%s",
353						argp->map_parms.map,
354						argp->map_parms.domain);
355		yp_error("host at %s (%s) may be pulling my leg",
356						argp->map_parms.peer,
357						inet_ntoa(rqhost->sin_addr));
358		YPXFR_RETURN(YPXFR_REFUSED)
359	}
360
361	switch (yp_fork()) {
362	case 0:
363	{
364		char g[11], t[11], p[11];
365		char ypxfr_command[MAXPATHLEN + 2];
366
367		snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC);
368		snprintf (t, sizeof(t), "%u", argp->transid);
369		snprintf (g, sizeof(g), "%u", argp->prog);
370		snprintf (p, sizeof(p), "%u", argp->port);
371		if (debug) {
372			close(0); close(1); close(2);
373		}
374		if (strcmp(yp_dir, _PATH_YP)) {
375			execl(ypxfr_command, "ypxfr",
376			"-d", argp->map_parms.domain,
377		      	"-h", mres->peer,
378			"-p", yp_dir, "-C", t,
379		      	g, inet_ntoa(rqhost->sin_addr),
380			p, argp->map_parms.map,
381		      	(char *)NULL);
382		} else {
383			execl(ypxfr_command, "ypxfr",
384			"-d", argp->map_parms.domain,
385		      	"-h", mres->peer,
386			"-C", t,
387		      	g, inet_ntoa(rqhost->sin_addr),
388			p, argp->map_parms.map,
389		      	(char *)NULL);
390		}
391		yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
392		YPXFR_RETURN(YPXFR_XFRERR)
393		/*
394		 * Just to safe, prevent PR #10970 from biting us in
395		 * the unlikely case that execing ypxfr fails. We don't
396		 * want to have any child processes spawned from this
397		 * child process.
398		 */
399		_exit(0);
400		break;
401	}
402	case -1:
403		yp_error("ypxfr fork(): %s", strerror(errno));
404		YPXFR_RETURN(YPXFR_XFRERR)
405		break;
406	default:
407		result.xfrstat = YPXFR_SUCC;
408		children++;
409		break;
410	}
411
412	return (&result);
413}
414#undef YPXFR_RETURN
415
416void *
417ypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
418{
419	static char * result;
420	static char rval = 0;
421
422#ifdef DB_CACHE
423	if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
424#else
425	if (yp_access(NULL, (struct svc_req *)rqstp))
426#endif
427		return (NULL);
428#ifdef DB_CACHE
429	/* clear out the database cache */
430	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