yp_server.c revision 12891
1173147Srwatson/*
2156287Srwatson * Copyright (c) 1995
3156287Srwatson *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
4156287Srwatson *
5156287Srwatson * Redistribution and use in source and binary forms, with or without
6156287Srwatson * modification, are permitted provided that the following conditions
7244390Srwatson * are met:
8244390Srwatson * 1. Redistributions of source code must retain the above copyright
9244390Srwatson *    notice, this list of conditions and the following disclaimer.
10244390Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11244390Srwatson *    notice, this list of conditions and the following disclaimer in the
12244390Srwatson *    documentation and/or other materials provided with the distribution.
13156287Srwatson * 3. All advertising materials mentioning features or use of this software
14195740Srwatson *    must display the following acknowledgement:
15156287Srwatson *	This product includes software developed by Bill Paul.
16156287Srwatson * 4. Neither the name of the author nor the names of any co-contributors
17156287Srwatson *    may be used to endorse or promote products derived from this software
18156287Srwatson *    without specific prior written permission.
19244390Srwatson *
20244390Srwatson * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21244390Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22156287Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23156287Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
24156287Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25161634Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26161634Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27161634Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28244390Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29244390Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30244390Srwatson * SUCH DAMAGE.
31156287Srwatson *
32156287Srwatson */
33156287Srwatson
34156287Srwatson#include "yp_extern.h"
35156287Srwatson#include "yp.h"
36156287Srwatson#include <stdlib.h>
37244390Srwatson#include <dirent.h>
38244390Srwatson#include <sys/stat.h>
39244390Srwatson#include <sys/param.h>
40244390Srwatson#include <errno.h>
41244390Srwatson#include <sys/types.h>
42244390Srwatson#include <sys/socket.h>
43156287Srwatson#include <netinet/in.h>
44156287Srwatson#include <arpa/inet.h>
45156287Srwatson
46244390Srwatson#ifndef lint
47244390Srwatsonstatic char rcsid[] = "$Id: yp_server.c,v 1.18 1995/12/16 04:01:55 wpaul Exp $";
48244390Srwatson#endif /* not lint */
49156287Srwatson
50156287Srwatsonint forked = 0;
51156287Srwatsonint children = 0;
52156287SrwatsonDB *spec_dbp = NULL;	/* Special global DB handle for ypproc_all. */
53195740Srwatson
54156287Srwatsonvoid *
55244390Srwatsonypproc_null_2_svc(void *argp, struct svc_req *rqstp)
56244390Srwatson{
57244390Srwatson	static char * result;
58244390Srwatson	static char rval = 0;
59244390Srwatson
60244390Srwatson	if (yp_access(NULL, (struct svc_req *)rqstp))
61156287Srwatson		return(NULL);
62156287Srwatson
63156287Srwatson	result = &rval;
64156287Srwatson
65156287Srwatson	return((void *) &result);
66156287Srwatson}
67156287Srwatson
68156287Srwatsonbool_t *
69156287Srwatsonypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
70185573Srwatson{
71185573Srwatson	static bool_t  result;
72185573Srwatson
73185573Srwatson	if (yp_access(NULL, (struct svc_req *)rqstp)) {
74185573Srwatson		result = FALSE;
75185573Srwatson		return (&result);
76156287Srwatson	}
77156287Srwatson
78156287Srwatson	if (argp == NULL || yp_validdomain(*argp))
79156287Srwatson		result = FALSE;
80156287Srwatson	else
81156287Srwatson		result = TRUE;
82244390Srwatson
83244390Srwatson	return (&result);
84244390Srwatson}
85244390Srwatson
86244390Srwatsonbool_t *
87244390Srwatsonypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
88156287Srwatson{
89156287Srwatson	static bool_t  result;
90156287Srwatson
91156287Srwatson	if (yp_access(NULL, (struct svc_req *)rqstp))
92156287Srwatson		return (NULL);
93156287Srwatson
94156287Srwatson	if (argp == NULL || yp_validdomain(*argp))
95156287Srwatson		return (NULL);
96156287Srwatson	else
97156287Srwatson		result = TRUE;
98156287Srwatson
99156287Srwatson	return (&result);
100156287Srwatson}
101156287Srwatson
102156287Srwatsonypresp_val *
103156287Srwatsonypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
104244390Srwatson{
105244390Srwatson	static ypresp_val  result;
106244390Srwatson	DBT key, data;
107244390Srwatson
108244390Srwatson	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
109244390Srwatson		result.stat = YP_YPERR;
110244390Srwatson		return (&result);
111244390Srwatson	}
112244390Srwatson
113244390Srwatson	if (argp->domain == NULL || argp->map == NULL) {
114244390Srwatson		result.stat = YP_BADARGS;
115244390Srwatson		return (&result);
116244390Srwatson	}
117186648Srwatson
118186648Srwatson	if (yp_validdomain(argp->domain)) {
119186648Srwatson		result.stat = YP_NODOM;
120244390Srwatson		return(&result);
121244390Srwatson	}
122244390Srwatson
123244390Srwatson	key.size = argp->key.keydat_len;
124244390Srwatson	key.data = argp->key.keydat_val;
125244390Srwatson
126244390Srwatson	result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 0);
127244390Srwatson
128244390Srwatson	if (result.stat == YP_TRUE) {
129244390Srwatson		result.val.valdat_len = data.size;
130244390Srwatson		result.val.valdat_val = data.data;
131244390Srwatson	}
132244390Srwatson
133244390Srwatson	/*
134244390Srwatson	 * Do DNS lookups for hosts maps if database lookup failed.
135156287Srwatson	 */
136156287Srwatson
137156287Srwatson	if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) {
138156287Srwatson		char *rval;
139156287Srwatson
140156287Srwatson	/* DNS lookups can take time -- do them in a subprocess */
141156287Srwatson
142156287Srwatson		if (!debug && children < MAX_CHILDREN && fork()) {
143156287Srwatson			children++;
144156287Srwatson			forked = 0;
145156287Srwatson			/*
146156287Srwatson			 * Returning NULL here prevents svc_sendreply()
147156287Srwatson			 * from being called by the parent. This is vital
148156287Srwatson			 * since having both the parent and the child process
149156287Srwatson			 * call it would confuse the client.
150156287Srwatson			 */
151156287Srwatson			return (NULL);
152156287Srwatson		} else {
153156287Srwatson			forked++;
154156287Srwatson		}
155156287Srwatson
156156287Srwatson		if (debug)
157156287Srwatson			yp_error("Doing DNS lookup of %.*s",
158156287Srwatson			 	  argp->key.keydat_len,
159156287Srwatson				  argp->key.keydat_val);
160162507Srwatson
161162507Srwatson		/* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
162162507Srwatson		argp->key.keydat_val[argp->key.keydat_len] = '\0';
163185573Srwatson
164185573Srwatson		if (!strcmp(argp->map, "hosts.byname"))
165185573Srwatson			rval = yp_dnsname((char *)argp->key.keydat_val);
166244390Srwatson		else if (!strcmp(argp->map, "hosts.byaddr"))
167244390Srwatson			rval = yp_dnsaddr((const char *)argp->key.keydat_val);
168244390Srwatson
169156287Srwatson
170156287Srwatson		if (rval) {
171156287Srwatson			if (debug)
172156287Srwatson				yp_error("DNS lookup successful. Result: %s", rval);
173156287Srwatson			result.val.valdat_len = strlen(rval);
174156287Srwatson			result.val.valdat_val = rval;
175156287Srwatson			result.stat = YP_TRUE;
176156287Srwatson		} else {
177156287Srwatson			if (debug)
178156287Srwatson				yp_error("DNS lookup failed.");
179156287Srwatson			result.stat = YP_NOKEY;
180156287Srwatson		}
181244390Srwatson	}
182156287Srwatson
183156287Srwatson	return (&result);
184156287Srwatson}
185156287Srwatson
186156287Srwatsonypresp_key_val *
187156287Srwatsonypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
188156287Srwatson{
189156287Srwatson	static ypresp_key_val  result;
190156287Srwatson	DBT key, data;
191156287Srwatson	DB *dbp;
192156287Srwatson
193156287Srwatson	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
194156287Srwatson		result.stat = YP_YPERR;
195156287Srwatson		return (&result);
196156287Srwatson	}
197156287Srwatson
198156287Srwatson	if (argp->domain == NULL) {
199156287Srwatson		result.stat = YP_BADARGS;
200156287Srwatson		return (&result);
201156287Srwatson	}
202244390Srwatson
203244390Srwatson	if (yp_validdomain(argp->domain)) {
204244390Srwatson		result.stat = YP_NODOM;
205156287Srwatson		return(&result);
206156287Srwatson	}
207156287Srwatson
208156287Srwatson	if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
209156287Srwatson		result.stat = yp_errno;
210156287Srwatson		return(&result);
211244390Srwatson	}
212244390Srwatson
213244390Srwatson	key.data = NULL;
214156287Srwatson	key.size = 0;
215156287Srwatson	result.stat = yp_first_record(dbp, &key, &data);
216156287Srwatson	(void)(dbp->close)(dbp);
217156287Srwatson
218156287Srwatson	if (result.stat == YP_TRUE) {
219156287Srwatson		result.key.keydat_len = key.size;
220156287Srwatson		result.key.keydat_val = key.data;
221156287Srwatson		result.val.valdat_len = data.size;
222195740Srwatson		result.val.valdat_val = data.data;
223156287Srwatson	}
224244390Srwatson
225244390Srwatson	return (&result);
226244390Srwatson}
227244390Srwatson
228156287Srwatsonypresp_key_val *
229156287Srwatsonypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
230156287Srwatson{
231156287Srwatson	static ypresp_key_val  result;
232156287Srwatson	DBT key, data;
233156287Srwatson	DB *dbp;
234156287Srwatson
235156287Srwatson	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
236156287Srwatson		result.stat = YP_YPERR;
237156287Srwatson		return (&result);
238244390Srwatson	}
239156287Srwatson
240156287Srwatson	if (argp->domain == NULL || argp->map == NULL) {
241156287Srwatson		result.stat = YP_BADARGS;
242156287Srwatson		return (&result);
243244390Srwatson	}
244244390Srwatson
245244390Srwatson	if (yp_validdomain(argp->domain)) {
246156287Srwatson		result.stat = YP_NODOM;
247244390Srwatson		return(&result);
248156287Srwatson	}
249156287Srwatson
250156287Srwatson	if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
251156287Srwatson		result.stat = yp_errno;
252156287Srwatson		return(&result);
253156287Srwatson	}
254156287Srwatson
255156287Srwatson	key.size = argp->key.keydat_len;
256156287Srwatson	key.data = argp->key.keydat_val;
257156287Srwatson
258156287Srwatson	result.stat = yp_next_record(dbp, &key, &data, 0);
259156287Srwatson	(void)(dbp->close)(dbp);
260156287Srwatson
261244390Srwatson	if (result.stat == YP_TRUE) {
262244390Srwatson		result.key.keydat_len = key.size;
263244390Srwatson		result.key.keydat_val = key.data;
264244390Srwatson		result.val.valdat_len = data.size;
265244390Srwatson		result.val.valdat_val = data.data;
266244390Srwatson	}
267244390Srwatson
268244390Srwatson	return (&result);
269244390Srwatson}
270244390Srwatson
271244390Srwatsonypresp_xfr *
272244390Srwatsonypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
273185573Srwatson{
274185573Srwatson	static ypresp_xfr  result;
275185573Srwatson
276185573Srwatson	if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
277244390Srwatson		result.xfrstat = YPXFR_REFUSED;
278185573Srwatson		return(&result);
279244390Srwatson	}
280244390Srwatson
281244390Srwatson	if (argp->map_parms.domain == NULL) {
282156287Srwatson		result.xfrstat = YPXFR_BADARGS;
283244390Srwatson		return (&result);
284156287Srwatson	}
285244390Srwatson
286244390Srwatson	if (yp_validdomain(argp->map_parms.domain)) {
287244390Srwatson		result.xfrstat = YPXFR_NODOM;
288244390Srwatson		return(&result);
289195740Srwatson	}
290195740Srwatson
291195740Srwatson	switch(fork()) {
292156287Srwatson	case 0:
293156287Srwatson	{
294156287Srwatson		char g[11], t[11], p[11];
295156287Srwatson		struct sockaddr_in *rqhost;
296156287Srwatson		char ypxfr_command[MAXPATHLEN + 2];
297156287Srwatson
298156287Srwatson		rqhost = svc_getcaller(rqstp->rq_xprt);
299156287Srwatson		sprintf (ypxfr_command, "%sypxfr", _PATH_LIBEXEC);
300156287Srwatson		sprintf (t, "%u", argp->transid);
301156287Srwatson		sprintf (g, "%u", argp->prog);
302156287Srwatson		sprintf (p, "%u", argp->port);
303156287Srwatson		children++;
304173147Srwatson		forked = 0;
305156287Srwatson		execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain,
306156287Srwatson		      "-h", argp->map_parms.peer, "-f", "-C", t, g,
307156287Srwatson		      inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map,
308156287Srwatson		      NULL);
309156287Srwatson		yp_error("ypxfr execl(): %s", strerror(errno));
310156287Srwatson		return(NULL);
311156287Srwatson	}
312	case -1:
313		yp_error("ypxfr fork(): %s", strerror(errno));
314		result.xfrstat = YPXFR_XFRERR;
315		break;
316	default:
317		result.xfrstat = YPXFR_SUCC;
318		forked++;
319		break;
320	}
321
322	result.transid = argp->transid;
323	return (&result);
324}
325
326void *
327ypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
328{
329	static char * result;
330	static char rval = 0;
331
332	/*
333	 * We don't have to do anything for ypproc_clear. Unlike
334	 * the SunOS ypserv, we don't hold out database descriptors
335	 * open forever.
336	 */
337	if (yp_access(NULL, (struct svc_req *)rqstp))
338		return (NULL);
339
340	result = &rval;
341	return((void *) &result);
342}
343
344/*
345 * For ypproc_all, we have to send a stream of ypresp_all structures
346 * via TCP, but the XDR filter generated from the yp.x protocol
347 * definition file only serializes one such structure. This means that
348 * to send the whole stream, you need a wrapper which feeds all the
349 * records into the underlying XDR routine until it hits an 'EOF.'
350 * But to use the wrapper, you have to violate the boundaries between
351 * RPC layers by calling svc_sendreply() directly from the ypproc_all
352 * service routine instead of letting the RPC dispatcher do it.
353 *
354 * Bleah.
355 */
356
357/*
358 * Custom XDR routine for serialzing results of ypproc_all: keep
359 * reading from the database and spew until we run out of records
360 * or encounter an error.
361 */
362static bool_t
363xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
364{
365	DBT key, data;
366
367	while (1) {
368		/* Get a record. */
369		key.size = objp->ypresp_all_u.val.key.keydat_len;
370		key.data = objp->ypresp_all_u.val.key.keydat_val;
371
372		if ((objp->ypresp_all_u.val.stat =
373		    yp_next_record(spec_dbp,&key,&data,1)) == YP_TRUE) {
374			objp->ypresp_all_u.val.val.valdat_len = data.size;
375			objp->ypresp_all_u.val.val.valdat_val = data.data;
376			objp->ypresp_all_u.val.key.keydat_len = key.size;
377			objp->ypresp_all_u.val.key.keydat_val = key.data;
378			objp->more = TRUE;
379		} else {
380			objp->more = FALSE;
381		}
382
383		/* Serialize. */
384		if (!xdr_ypresp_all(xdrs, objp))
385			return(FALSE);
386		if (objp->more == FALSE)
387			return(TRUE);
388	}
389}
390
391ypresp_all *
392ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
393{
394	static ypresp_all  result;
395
396	/*
397	 * Set this here so that the client will be forced to make
398	 * at least one attempt to read from us even if all we're
399	 * doing is returning an error.
400	 */
401	result.more = TRUE;
402
403	if (yp_access(argp->map, (struct svc_req *)rqstp)) {
404		result.ypresp_all_u.val.stat = YP_YPERR;
405		return (&result);
406	}
407
408	if (argp->domain == NULL || argp->map == NULL) {
409		result.ypresp_all_u.val.stat = YP_BADARGS;
410		return (&result);
411	}
412
413	if (yp_validdomain(argp->domain)) {
414		result.ypresp_all_u.val.stat = YP_NODOM;
415		return(&result);
416	}
417
418	/*
419	 * The ypproc_all procedure can take a while to complete.
420	 * Best to handle it in a subprocess so the parent doesn't
421	 * block. We fork() here so we don't end up sharing a
422	 * DB file handle with the parent.
423	 */
424
425	if (!debug && children < MAX_CHILDREN && fork()) {
426		children++;
427		forked = 0;
428		return (NULL);
429	} else {
430		forked++;
431	}
432
433	if ((spec_dbp = yp_open_db(argp->domain, argp->map)) == NULL) {
434		result.ypresp_all_u.val.stat = yp_errno;
435		return(&result);
436	}
437
438	/* Kick off the actual data transfer. */
439	svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result);
440
441	/* Close database when done. */
442	(void)(spec_dbp->close)(spec_dbp);
443
444	/*
445	 * Returning NULL prevents the dispatcher from calling
446	 * svc_sendreply() since we already did it.
447	 */
448	return (NULL);
449}
450
451ypresp_master *
452ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
453{
454	static ypresp_master  result;
455	DBT key,data;
456
457	if (yp_access(NULL, (struct svc_req *)rqstp)) {
458		result.stat = YP_YPERR;
459		return(&result);
460	}
461
462	if (argp->domain == NULL) {
463		result.stat = YP_BADARGS;
464		return (&result);
465	}
466
467	if (yp_validdomain(argp->domain)) {
468		result.stat = YP_NODOM;
469		return (&result);
470	}
471
472	key.data = "YP_MASTER_NAME";
473	key.size = sizeof("YP_MASTER_NAME") - 1;
474
475	result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 1);
476
477	if (result.stat == YP_TRUE) {
478		result.peer = (char *)data.data;
479		result.peer[data.size] = '\0';
480	} else
481		result.peer = "";
482
483	return (&result);
484}
485
486ypresp_order *
487ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
488{
489	static ypresp_order  result;
490	DBT key,data;
491
492	if (yp_access(NULL, (struct svc_req *)rqstp)) {
493		result.stat = YP_YPERR;
494		return(&result);
495	}
496
497	if (argp->domain == NULL) {
498		result.stat = YP_BADARGS;
499		return (&result);
500	}
501
502	if (yp_validdomain(argp->domain)) {
503		result.stat = YP_NODOM;
504		return (&result);
505	}
506
507	/*
508	 * We could just check the timestamp on the map file,
509	 * but that's a hack: we'll only know the last time the file
510	 * was touched, not the last time the database contents were
511	 * updated.
512	 */
513	key.data = "YP_LAST_MODIFIED";
514	key.size = sizeof("YP_LAST_MODIFIED") - 1;
515
516	result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 1);
517
518	if (result.stat == YP_TRUE)
519		result.ordernum = atoi((char *)data.data);
520	else
521		result.ordernum = 0;
522
523	return (&result);
524}
525
526static void yp_maplist_free(yp_maplist)
527	struct ypmaplist *yp_maplist;
528{
529	register struct ypmaplist *next;
530
531	while(yp_maplist) {
532		next = yp_maplist->next;
533		free(yp_maplist->map);
534		free(yp_maplist);
535		yp_maplist = next;
536	}
537	return;
538}
539
540static struct ypmaplist *yp_maplist_create(domain)
541	const char *domain;
542{
543	char yp_mapdir[MAXPATHLEN + 2];
544	char yp_mapname[MAXPATHLEN + 2];
545	struct ypmaplist *cur = NULL;
546	struct ypmaplist *yp_maplist = NULL;
547	DIR *dird;
548	struct dirent *dirp;
549	struct stat statbuf;
550
551	snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
552
553	if ((dird = opendir(yp_mapdir)) == NULL) {
554		yp_error("opendir(%s) failed: %s", strerror(errno));
555		return(NULL);
556	}
557
558	while ((dirp = readdir(dird)) != NULL) {
559		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
560			snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",yp_mapdir,dirp->d_name);
561			if (stat(yp_mapname, &statbuf) < 0 || !S_ISREG(statbuf.st_mode))
562				continue;
563			if ((cur = (struct ypmaplist *)malloc(sizeof(struct ypmaplist))) < 0) {
564				yp_error("malloc() failed: %s", strerror(errno));
565				closedir(dird);
566				yp_maplist_free(yp_maplist);
567				return(NULL);
568			}
569			if ((cur->map = (char *)strdup(dirp->d_name)) == NULL) {
570				yp_error("strdup() failed: %s", strerror(errno));
571				closedir(dird);
572				yp_maplist_free(yp_maplist);
573				return(NULL);
574			}
575			cur->next = yp_maplist;
576			yp_maplist = cur;
577			if (debug)
578				yp_error("map: %s", yp_maplist->map);
579		}
580
581	}
582	closedir(dird);
583	return(yp_maplist);
584}
585
586ypresp_maplist *
587ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
588{
589	static ypresp_maplist  result;
590
591	if (yp_access(NULL, (struct svc_req *)rqstp)) {
592		result.stat = YP_YPERR;
593		return(&result);
594	}
595
596	if (argp == NULL) {
597		result.stat = YP_BADARGS;
598		return (&result);
599	}
600
601	if (yp_validdomain(*argp)) {
602		result.stat = YP_NODOM;
603		return (&result);
604	}
605
606	/*
607	 * We have to construct a linked list for the ypproc_maplist
608	 * procedure using dynamically allocated memory. Since the XDR
609	 * layer won't free this list for us, we have to deal with it
610	 * ourselves. We call yp_maplist_free() first to free any
611	 * previously allocated data we may have accumulated to insure
612	 * that we have only one linked list in memory at any given
613	 * time.
614	 */
615
616	yp_maplist_free(result.maps);
617
618	if ((result.maps = yp_maplist_create(*argp)) == NULL) {
619		yp_error("yp_maplist_create failed");
620		result.stat = YP_YPERR;
621		return(&result);
622	} else
623		result.stat = YP_TRUE;
624
625	return (&result);
626}
627