rpcb_svc_com.c revision 11262:b7ebfbf2359e
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26/* All Rights Reserved */
27/*
28 * University Copyright- Copyright (c) 1982, 1986, 1988
29 * The Regents of the University of California
30 * All Rights Reserved
31 *
32 * University Acknowledgment- Portions of this document are derived from
33 * software developed by the University of California, Berkeley, and its
34 * contributors.
35 */
36
37/*
38 * rpcb_svc_com.c
39 * The commom server procedure for the rpcbind.
40 */
41
42#include <stdio.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <unistd.h>
46#include <stdlib.h>
47#include <string.h>
48#include <strings.h>
49#include <rpc/rpc.h>
50#include <rpc/rpcb_prot.h>
51#include <rpcsvc/svc_dg_priv.h>
52#include <netconfig.h>
53#include <sys/param.h>
54#include <errno.h>
55#include <zone.h>
56#include <sys/poll.h>
57#include <sys/stropts.h>
58#ifdef PORTMAP
59#include <netinet/in.h>
60#include <rpc/pmap_prot.h>
61#endif /* PORTMAP */
62#include <syslog.h>
63#include <netdir.h>
64#include <ucred.h>
65#include <alloca.h>
66#include <rpcsvc/yp_prot.h>
67#include <nfs/nfs.h>
68#include <nfs/nfs_acl.h>
69#include <rpcsvc/mount.h>
70#include <nfs/nfs_acl.h>
71#include <rpc/key_prot.h>
72#include <rpcsvc/yp_prot.h>
73#include <rpcsvc/rquota.h>
74#include <rpcsvc/yppasswd.h>
75#include <rpcsvc/ypupd.h>
76#include "rpcbind.h"
77
78static bool_t	xdr_opaque_parms();
79char	*getowner();
80static ulong_t	forward_register();
81static void	handle_reply();
82static int	netbufcmp();
83static int	free_slot_by_xid();
84static int	free_slot_by_index();
85static int	check_rmtcalls();
86static void	netbuffree();
87static void	find_versions();
88static struct netbuf	*netbufdup();
89static rpcblist_ptr find_service();
90static int	add_pmaplist(RPCB *);
91int	del_pmaplist(RPCB *);
92void	delete_rbl(rpcblist_ptr);
93
94static char *nullstring = "";
95static int rpcb_rmtcalls;
96
97/*
98 * Set a mapping of program, version, netid
99 */
100/* ARGSUSED */
101bool_t *
102rpcbproc_set_com(regp, rqstp, transp, rpcbversnum)
103	RPCB *regp;
104	struct svc_req *rqstp;	/* Not used here */
105	SVCXPRT *transp;
106	int rpcbversnum;
107{
108	static bool_t ans;
109	char owner[64];
110
111#ifdef RPCBIND_DEBUG
112	fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
113		regp->r_prog, regp->r_vers, regp->r_netid, regp->r_addr);
114#endif
115	ans = map_set(regp, getowner(transp, owner));
116#ifdef RPCBIND_DEBUG
117	fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
118#endif
119	/* XXX: should have used some defined constant here */
120	rpcbs_set((ulong_t)(rpcbversnum - 2), ans);
121	return (&ans);
122}
123
124bool_t
125map_set(regp, owner)
126	RPCB *regp;
127	char *owner;
128{
129	RPCB reg, *a;
130	rpcblist_ptr rbl, fnd;
131
132	reg = *regp;
133	/*
134	 * check to see if already used
135	 * find_service returns a hit even if
136	 * the versions don't match, so check for it
137	 */
138	fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
139	if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
140		if (strcmp(fnd->rpcb_map.r_addr, reg.r_addr) == 0)
141			/*
142			 * if these match then it is already
143			 * registered so just say "OK".
144			 */
145			return (TRUE);
146		else {
147			/*
148			 * Check if server is up.  If so, return FALSE.
149			 * If not, cleanup old registrations for the
150			 * program and register the new server.
151			 */
152			if (is_bound(fnd->rpcb_map.r_netid,
153							fnd->rpcb_map.r_addr))
154				return (FALSE);
155			delete_prog(reg.r_prog);
156			fnd = NULL;
157		}
158	}
159	/*
160	 * add to the end of the list
161	 */
162	rbl = (rpcblist_ptr) malloc((uint_t)sizeof (RPCBLIST));
163	if (rbl == (rpcblist_ptr)NULL) {
164		return (FALSE);
165	}
166	a = &(rbl->rpcb_map);
167	a->r_prog = reg.r_prog;
168	a->r_vers = reg.r_vers;
169	a->r_netid = strdup(reg.r_netid);
170	a->r_addr = strdup(reg.r_addr);
171	a->r_owner = strdup(owner);
172	if (a->r_addr == NULL || a->r_netid == NULL|| a->r_owner == NULL) {
173		delete_rbl(rbl);
174		return (FALSE);
175	}
176	rbl->rpcb_next = (rpcblist_ptr)NULL;
177	if (list_rbl == NULL) {
178		list_rbl = rbl;
179	} else {
180		for (fnd = list_rbl; fnd->rpcb_next;
181			fnd = fnd->rpcb_next)
182			;
183		fnd->rpcb_next = rbl;
184	}
185#ifdef PORTMAP
186	(void) add_pmaplist(regp);
187#endif
188	return (TRUE);
189}
190
191/*
192 * Unset a mapping of program, version, netid
193 */
194/* ARGSUSED */
195bool_t *
196rpcbproc_unset_com(regp, rqstp, transp, rpcbversnum)
197	RPCB *regp;
198	struct svc_req *rqstp;	/* Not used here */
199	SVCXPRT *transp;
200	int rpcbversnum;
201{
202	static bool_t ans;
203	char owner[64];
204
205#ifdef RPCBIND_DEBUG
206	fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
207		regp->r_prog, regp->r_vers, regp->r_netid);
208#endif
209	ans = map_unset(regp, getowner(transp, owner));
210#ifdef RPCBIND_DEBUG
211	fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
212#endif
213	/* XXX: should have used some defined constant here */
214	rpcbs_unset((ulong_t)(rpcbversnum - 2), ans);
215	return (&ans);
216}
217
218bool_t
219map_unset(regp, owner)
220	RPCB *regp;
221	char *owner;
222{
223#ifdef PORTMAP
224	int ans = 0;
225#endif
226	rpcblist_ptr rbl, next, prev = NULL;
227
228	if (owner == NULL)
229		return (0);
230
231	for (rbl = list_rbl; rbl != NULL; rbl = next) {
232		next = rbl->rpcb_next;
233
234		if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
235		    (rbl->rpcb_map.r_vers != regp->r_vers) ||
236		    (regp->r_netid[0] && strcasecmp(regp->r_netid,
237			rbl->rpcb_map.r_netid))) {
238			/* prev moves forwards */
239			prev = rbl;
240			continue;
241		}
242		/*
243		 * Check whether appropriate uid. Unset only
244		 * if superuser or the owner itself.
245		 */
246		if (strcmp(owner, "superuser") &&
247		    strcmp(rbl->rpcb_map.r_owner, owner))
248			return (0);
249		/* prev stays */
250#ifdef PORTMAP
251		ans = 1;
252#endif
253		delete_rbl(rbl);
254
255		if (prev == NULL)
256			list_rbl = next;
257		else
258			prev->rpcb_next = next;
259	}
260#ifdef PORTMAP
261	if (ans)
262		(void) del_pmaplist(regp);
263#endif
264	/*
265	 * We return 1 either when the entry was not there or it
266	 * was able to unset it.  It can come to this point only if
267	 * at least one of the conditions is true.
268	 */
269	return (1);
270}
271
272void
273delete_rbl(rpcblist_ptr rbl)
274{
275	free(rbl->rpcb_map.r_addr);
276	free(rbl->rpcb_map.r_netid);
277	free(rbl->rpcb_map.r_owner);
278	free(rbl);
279}
280
281void
282delete_prog(prog)
283	unsigned long prog;
284{
285	rpcblist_ptr rbl, next, prev = NULL;
286
287	for (rbl = list_rbl; rbl != NULL; rbl = next) {
288		next = rbl->rpcb_next;
289
290		if (rbl->rpcb_map.r_prog != prog ||
291		    is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr)) {
292			prev = rbl;
293			continue;
294		}
295
296#ifdef PORTMAP
297		(void) del_pmaplist(&rbl->rpcb_map);
298#endif
299		delete_rbl(rbl);
300
301		if (prev == NULL)
302			list_rbl = next;
303		else
304			prev->rpcb_next = next;
305	}
306}
307
308/*ARGSUSED*/
309char **
310rpcbproc_getaddr_com(regp, rqstp, transp, rpcbversnum, verstype)
311	RPCB *regp;
312	struct svc_req *rqstp;	/* Not used here */
313	SVCXPRT *transp;
314	ulong_t rpcbversnum;
315	ulong_t verstype;
316{
317	static char *uaddr;
318	char *saddr = NULL;
319	rpcblist_ptr fnd;
320	struct netconfig *trans_conf;	/* transport netconfig */
321
322	/*
323	 * There is a potential window at startup during which rpcbind
324	 * service has been established over IPv6 but not over IPv4.  If an
325	 * IPv4 request comes in during that window, the IP code will map
326	 * it into IPv6.  We could patch up the request so that it looks
327	 * like IPv4 (so that rpcbind returns an IPv4 uaddr to the caller),
328	 * but that requires some non-trivial code and it's hard to test.
329	 * Instead, drop the request on the floor and force the caller to
330	 * retransmit.  By the time rpcbind sees the retransmission, IPv4
331	 * service should be in place and it should see the request as
332	 * IPv4, as desired.
333	 */
334	trans_conf = rpcbind_get_conf(transp->xp_netid);
335	if (strcmp(trans_conf->nc_protofmly, NC_INET6) == 0) {
336		struct sockaddr_in6 *rmtaddr;
337
338		rmtaddr = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
339		if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) {
340			syslog(LOG_DEBUG,
341			    "IPv4 GETADDR request mapped to IPv6: ignoring");
342			return (NULL);
343		}
344	}
345
346	if (uaddr && uaddr[0])
347		free((void *) uaddr);
348	fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
349	if (fnd && ((verstype == RPCB_ALLVERS) ||
350		    (regp->r_vers == fnd->rpcb_map.r_vers))) {
351		if (*(regp->r_addr) != '\0') {  /* may contain a hint about */
352			saddr = regp->r_addr;   /* the interface that we    */
353		}				/* should use */
354		if (!(uaddr = mergeaddr(transp, transp->xp_netid,
355				fnd->rpcb_map.r_addr, saddr))) {
356			/* Try whatever we have */
357			uaddr = strdup(fnd->rpcb_map.r_addr);
358		} else if (!uaddr[0]) {
359			/*
360			 * The server died.  Unset all versions of this prog.
361			 */
362			delete_prog(regp->r_prog);
363			uaddr = nullstring;
364		}
365	} else {
366		uaddr = nullstring;
367	}
368#ifdef RPCBIND_DEBUG
369	fprintf(stderr, "getaddr: %s\n", uaddr);
370#endif
371	/* XXX: should have used some defined constant here */
372	rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers,
373		transp->xp_netid, uaddr);
374	return (&uaddr);
375}
376
377/* VARARGS */
378ulong_t *
379rpcbproc_gettime_com()
380{
381	static time_t curtime;
382
383	(void) time(&curtime);
384	return ((ulong_t *)&curtime);
385}
386
387/*
388 * Convert uaddr to taddr. Should be used only by
389 * local servers/clients. (kernel level stuff only)
390 */
391/* ARGSUSED */
392struct netbuf *
393rpcbproc_uaddr2taddr_com(uaddrp, rqstp, transp, rpcbversnum)
394	char **uaddrp;
395	struct svc_req *rqstp;	/* Not used here */
396	SVCXPRT *transp;
397	int rpcbversnum;	/* Not used here */
398{
399	struct netconfig *nconf;
400	static struct netbuf nbuf;
401	static struct netbuf *taddr;
402
403	if (taddr) {
404		free((void *) taddr->buf);
405		free((void *) taddr);
406	}
407	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
408	    ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
409		(void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
410		return (&nbuf);
411	}
412	return (taddr);
413}
414
415/*
416 * Convert taddr to uaddr. Should be used only by
417 * local servers/clients. (kernel level stuff only)
418 */
419/* ARGSUSED */
420char **
421rpcbproc_taddr2uaddr_com(taddr, rqstp, transp, rpcbversnum)
422	struct netbuf *taddr;
423	struct svc_req *rqstp;	/* Not used here */
424	SVCXPRT *transp;
425	int rpcbversnum; /* unused */
426{
427	static char *uaddr;
428	struct netconfig *nconf;
429
430#ifdef CHEW_FDS
431	int fd;
432
433	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
434		uaddr = (char *)strerror(errno);
435		return (&uaddr);
436	}
437#endif /* CHEW_FDS */
438	if (uaddr && uaddr[0])
439		free((void *) uaddr);
440	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
441		((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
442		uaddr = nullstring;
443	}
444	return (&uaddr);
445}
446
447
448/*
449 * Stuff for the rmtcall service
450 */
451struct encap_parms {
452	ulong_t arglen;
453	char *args;
454};
455
456static bool_t
457xdr_encap_parms(xdrs, epp)
458	XDR *xdrs;
459	struct encap_parms *epp;
460{
461	return (xdr_bytes(xdrs, &(epp->args), (uint_t *)&(epp->arglen), ~0));
462}
463
464
465struct r_rmtcall_args {
466	ulong_t 	rmt_prog;
467	ulong_t 	rmt_vers;
468	ulong_t 	rmt_proc;
469	int	rmt_localvers;	/* whether to send port # or uaddr */
470	char 	*rmt_uaddr;
471	struct encap_parms rmt_args;
472};
473
474/*
475 * XDR remote call arguments.  It ignores the address part.
476 * written for XDR_DECODE direction only
477 */
478static bool_t
479xdr_rmtcall_args(xdrs, cap)
480	register XDR *xdrs;
481	register struct r_rmtcall_args *cap;
482{
483	/* does not get the address or the arguments */
484	if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
485	    xdr_u_long(xdrs, &(cap->rmt_vers)) &&
486	    xdr_u_long(xdrs, &(cap->rmt_proc))) {
487		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
488	}
489	return (FALSE);
490}
491
492/*
493 * XDR remote call results along with the address.  Ignore
494 * program number, version  number and proc number.
495 * Written for XDR_ENCODE direction only.
496 */
497static bool_t
498xdr_rmtcall_result(xdrs, cap)
499	register XDR *xdrs;
500	register struct r_rmtcall_args *cap;
501{
502	bool_t result;
503
504#ifdef PORTMAP
505	if (cap->rmt_localvers == PMAPVERS) {
506		int h1, h2, h3, h4, p1, p2;
507		ulong_t port;
508
509		/* interpret the universal address for TCP/IP */
510		if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
511			&h1, &h2, &h3, &h4, &p1, &p2) != 6)
512			return (FALSE);
513		port = ((p1 & 0xff) << 8) + (p2 & 0xff);
514		result = xdr_u_long(xdrs, &port);
515	} else
516#endif
517		if ((cap->rmt_localvers == RPCBVERS) ||
518		    (cap->rmt_localvers == RPCBVERS4)) {
519		result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
520	} else {
521		return (FALSE);
522	}
523	if (result == TRUE)
524		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
525	return (FALSE);
526}
527
528/*
529 * only worries about the struct encap_parms part of struct r_rmtcall_args.
530 * The arglen must already be set!!
531 */
532static bool_t
533xdr_opaque_parms(xdrs, cap)
534	XDR *xdrs;
535	struct r_rmtcall_args *cap;
536{
537	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
538}
539
540struct rmtcallfd_list {
541	int fd;
542	SVCXPRT *xprt;
543	char *netid;
544	struct rmtcallfd_list *next;
545};
546
547static struct rmtcallfd_list *rmthead;
548static struct rmtcallfd_list *rmttail;
549
550int
551create_rmtcall_fd(nconf)
552struct netconfig *nconf;
553{
554	int fd;
555	struct rmtcallfd_list *rmt;
556	SVCXPRT *xprt;
557
558	if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
559		if (debugging)
560			fprintf(stderr,
561	"create_rmtcall_fd: couldn't open \"%s\" (errno %d, t_errno %d)\n",
562			nconf->nc_device, errno, t_errno);
563		return (-1);
564	}
565	if (t_bind(fd, (struct t_bind *)0,
566		(struct t_bind *)0) == -1) {
567		if (debugging)
568			fprintf(stderr,
569"create_rmtcall_fd: couldn't bind to fd for \"%s\" (errno %d, t_errno %d)\n",
570				nconf->nc_device, errno, t_errno);
571		return (-1);
572	}
573	xprt = svc_tli_create(fd, 0, (struct t_bind *)0, 0, 0);
574	if (xprt == NULL) {
575		if (debugging)
576			fprintf(stderr,
577				"create_rmtcall_fd: svc_tli_create failed\n");
578		return (-1);
579	}
580	rmt = (struct rmtcallfd_list *)malloc((uint_t)
581		sizeof (struct rmtcallfd_list));
582	if (rmt == NULL) {
583		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
584		return (-1);
585	}
586	rmt->xprt = xprt;
587	rmt->netid = strdup(nconf->nc_netid);
588	xprt->xp_netid = rmt->netid;
589	rmt->fd = fd;
590	rmt->next = NULL;
591	if (rmthead == NULL) {
592		rmthead = rmt;
593		rmttail = rmt;
594	} else {
595		rmttail->next = rmt;
596		rmttail = rmt;
597	}
598#if defined(DEBUG_RMTCALL) && defined(PORTMAP)
599	if (debugging) {
600		struct sockaddr_in *sin;
601		struct netbuf *nb;
602		nb = &xprt->xp_ltaddr;
603		sin = (struct sockaddr_in *)nb->buf;
604		fprintf(stderr,
605			"create_rmtcall_fd %d, port %d\n",
606			fd, sin->sin_port);
607	}
608#endif
609	return (fd);
610}
611
612static int
613find_rmtcallfd_by_netid(netid)
614char *netid;
615{
616	struct rmtcallfd_list *rmt;
617
618	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
619		if (strcmp(netid, rmt->netid) == 0) {
620			return (rmt->fd);
621		}
622	}
623	return (-1);
624}
625
626static SVCXPRT *
627find_rmtcallxprt_by_fd(fd)
628int fd;
629{
630	struct rmtcallfd_list *rmt;
631
632	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
633		if (fd == rmt->fd) {
634			return (rmt->xprt);
635		}
636	}
637	return (NULL);
638}
639
640
641/*
642 * Call a remote procedure service.  This procedure is very quiet when things
643 * go wrong.  The proc is written to support broadcast rpc.  In the broadcast
644 * case, a machine should shut-up instead of complain, lest the requestor be
645 * overrun with complaints at the expense of not hearing a valid reply.
646 * When receiving a request and verifying that the service exists, we
647 *
648 *	receive the request
649 *
650 *	open a new TLI endpoint on the same transport on which we received
651 *	the original request
652 *
653 *	remember the original request's XID (which requires knowing the format
654 *	of the svc_dg_data structure)
655 *
656 *	forward the request, with a new XID, to the requested service,
657 *	remembering the XID used to send this request (for later use in
658 *	reassociating the answer with the original request), the requestor's
659 *	address, the file descriptor on which the forwarded request is
660 *	made and the service's address.
661 *
662 *	mark the file descriptor on which we anticipate receiving a reply from
663 *	the service and one to select for in our private svc_run procedure
664 *
665 * At some time in the future, a reply will be received from the service to
666 * which we forwarded the request.  At that time, we detect that the socket
667 * used was for forwarding (by looking through the finfo structures to see
668 * whether the fd corresponds to one of those) and call handle_reply() to
669 *
670 *	receive the reply
671 *
672 *	bundle the reply, along with the service's universal address
673 *
674 *	create a SVCXPRT structure and use a version of svc_sendreply
675 *	that allows us to specify the reply XID and destination, send the reply
676 *	to the original requestor.
677 */
678
679#define	RPC_BUF_MAX	65536	/* can be raised if required */
680
681/*
682 *  This is from ../ypcmd/yp_b.h
683 *  It does not appear in <rpcsvc/yp_prot.h>
684 */
685#define	YPBINDPROG ((ulong_t)100007)
686#define	YPBINDPROC_SETDOM ((ulong_t)2)
687
688void
689rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
690	struct svc_req *rqstp;
691	SVCXPRT *transp;
692	ulong_t reply_type;	/* which proc number */
693	ulong_t versnum;	/* which vers was called */
694{
695	register rpcblist_ptr rbl;
696	struct netconfig *nconf;
697	struct netbuf *caller;
698	struct r_rmtcall_args a;
699	char *buf_alloc = NULL;
700	char *outbuf_alloc = NULL;
701	char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
702	struct netbuf *na = (struct netbuf *)NULL;
703	struct t_info tinfo;
704	struct t_unitdata tu_data;
705	struct rpc_msg call_msg;
706	struct svc_dg_data *bd;
707	int outlen;
708	uint_t sendsz;
709	XDR outxdr;
710	AUTH *auth;
711	int fd = -1;
712	char *uaddr;
713	struct nd_mergearg ma;
714	int stat;
715
716	if (t_getinfo(transp->xp_fd, &tinfo) == -1) {
717		if (reply_type == RPCBPROC_INDIRECT)
718			svcerr_systemerr(transp);
719		return;
720	}
721	if (tinfo.servtype != T_CLTS)
722		return;	/* Only datagram type accepted */
723	sendsz = __rpc_get_t_size(0, tinfo.tsdu);
724	if (sendsz == 0) {	/* data transfer not supported */
725		if (reply_type == RPCBPROC_INDIRECT)
726			svcerr_systemerr(transp);
727		return;
728	}
729	/*
730	 * Should be multiple of 4 for XDR.
731	 */
732	sendsz = ((sendsz + 3) / 4) * 4;
733	if (sendsz > RPC_BUF_MAX) {
734#ifdef	notyet
735		buf_alloc = alloca(sendsz);		/* not in IDR2? */
736#else
737		buf_alloc = malloc(sendsz);
738#endif	/* notyet */
739		if (buf_alloc == NULL) {
740			if (debugging)
741				fprintf(stderr,
742					"rpcbproc_callit_com:  No Memory!\n");
743			if (reply_type == RPCBPROC_INDIRECT)
744				svcerr_systemerr(transp);
745			return;
746		}
747		a.rmt_args.args = buf_alloc;
748	} else {
749		a.rmt_args.args = buf;
750	}
751
752	call_msg.rm_xid = 0;	/* For error checking purposes */
753	ma.m_uaddr = NULL;
754	if (!svc_getargs(transp, (xdrproc_t)xdr_rmtcall_args, (char *)&a)) {
755		if (reply_type == RPCBPROC_INDIRECT)
756			svcerr_decode(transp);
757		if (debugging)
758			fprintf(stderr,
759			"rpcbproc_callit_com:  svc_getargs failed\n");
760		goto error;
761	}
762	if (!allow_indirect)
763		goto error;
764	caller = svc_getrpccaller(transp);
765#ifdef RPCBIND_DEBUG
766	uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
767	fprintf(stderr, "%s %s request for (%lu, %lu, %lu, %s) from %s : ",
768		versnum == PMAPVERS ? "pmap_rmtcall" :
769		versnum == RPCBVERS ? "rpcb_rmtcall" :
770		versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
771		reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
772		a.rmt_prog, a.rmt_vers, a.rmt_proc, transp->xp_netid,
773		uaddr ? uaddr : "unknown");
774	if (uaddr)
775		free((void *) uaddr);
776#endif
777
778	/*
779	 * Disallow calling rpcbind for certain procedures.
780	 * Allow calling NULLPROC - per man page on rpcb_rmtcall().
781	 * switch is in alphabetical order.
782	 */
783	if (a.rmt_proc != NULLPROC) {
784		switch (a.rmt_prog) {
785		case KEY_PROG:
786			if (debugging)
787				fprintf(stderr,
788					"rpcbind: rejecting KEY_PROG(%d)\n",
789					a.rmt_proc);
790			goto error;
791		case MOUNTPROG:
792			if (a.rmt_proc != MOUNTPROC_MNT)
793				break;
794			/*
795			 * In Solaris 2.6, the host-based accesss control
796			 * is done by the NFS server on each request.
797			 * Prior to 2.6 we rely on mountd.
798			 */
799			if (debugging)
800				fprintf(stderr,
801					"rpcbind: rejecting MOUNTPROG(%d)\n",
802					a.rmt_proc);
803			goto error;
804		case NFS_ACL_PROGRAM:
805			if (debugging)
806				fprintf(stderr,
807				"rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
808					a.rmt_proc);
809			goto error;
810		case NFS_PROGRAM:
811			/* also NFS3_PROGRAM */
812			if (debugging)
813				fprintf(stderr,
814					"rpcbind: rejecting NFS_PROGRAM(%d)\n",
815					a.rmt_proc);
816			goto error;
817		case RPCBPROG:
818			/*
819			 * Disallow calling rpcbind for certain procedures.
820			 * Luckily Portmap set/unset/callit also have same
821			 * procedure numbers.  So, will not check for those.
822			 */
823			switch (a.rmt_proc) {
824			case RPCBPROC_SET:
825			case RPCBPROC_UNSET:
826			case RPCBPROC_CALLIT:
827			case RPCBPROC_INDIRECT:
828				if (reply_type == RPCBPROC_INDIRECT)
829					svcerr_weakauth(transp); /* XXX */
830				if (debugging)
831					fprintf(stderr,
832"rpcbproc_callit_com: calling RPCBPROG procs SET, UNSET, CALLIT, or INDIRECT \
833not allowed	\n");
834				goto error;
835			default:
836				/*
837				 * Ideally, we should have called rpcb_service()
838				 * or pmap_service() with appropriate parameters
839				 * instead of going about in a roundabout
840				 * manner.  Hopefully, this case should happen
841				 * rarely.
842				 */
843				break;
844			}
845			break;
846		case RQUOTAPROG:
847			if (debugging)
848				fprintf(stderr,
849					"rpcbind: rejecting RQUOTAPROG(%d)\n",
850					a.rmt_proc);
851			goto error;
852		case YPPASSWDPROG:
853			if (debugging)
854				fprintf(stderr,
855					"rpcbind: rejecting YPPASSWDPROG(%d)\n",
856					a.rmt_proc);
857			goto error;
858		case YPU_PROG:
859			if (debugging)
860				fprintf(stderr,
861					"rpcbind: rejecting YPU_PROG(%d)\n",
862					a.rmt_proc);
863			goto error;
864		case YPBINDPROG:
865			if (a.rmt_proc != YPBINDPROC_SETDOM)
866				break;
867			if (debugging)
868				fprintf(stderr,
869					"rpcbind: rejecting YPBINDPROG(%d)\n",
870					a.rmt_proc);
871			goto error;
872		case YPPROG:
873			switch (a.rmt_proc) {
874			case YPPROC_FIRST:
875			case YPPROC_NEXT:
876			case YPPROC_MATCH:
877			case YPPROC_ALL:
878				if (debugging)
879					fprintf(stderr,
880					"rpcbind: rejecting YPPROG(%d)\n",
881						a.rmt_proc);
882				goto error;
883			default:
884				break;
885			}
886			break;
887		default:
888			break;
889		}
890	}
891
892	rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
893
894	rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
895			a.rmt_proc, transp->xp_netid, rbl);
896
897	if (rbl == (rpcblist_ptr)NULL) {
898#ifdef RPCBIND_DEBUG
899		fprintf(stderr, "not found\n");
900#endif
901		if (reply_type == RPCBPROC_INDIRECT)
902			svcerr_noprog(transp);
903		goto error;
904	}
905	if (rbl->rpcb_map.r_vers != a.rmt_vers) {
906#ifdef RPCBIND_DEBUG
907		fprintf(stderr, "version not found\n");
908#endif
909		if (reply_type == RPCBPROC_INDIRECT) {
910			ulong_t vers_low, vers_high;
911
912			find_versions(a.rmt_prog, transp->xp_netid,
913				&vers_low, &vers_high);
914			svcerr_progvers(transp, vers_low, vers_high);
915		}
916		goto error;
917	}
918
919#ifdef RPCBIND_DEBUG
920	fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
921#endif
922	/*
923	 *	Check whether this entry is valid and a server is present
924	 *	Mergeaddr() returns NULL if no such entry is present, and
925	 *	returns "" if the entry was present but the server is not
926	 *	present (i.e., it crashed).
927	 */
928	if (reply_type == RPCBPROC_INDIRECT) {
929		uaddr = mergeaddr(transp, transp->xp_netid,
930			rbl->rpcb_map.r_addr, NULL);
931		if ((uaddr == (char *)NULL) || uaddr[0] == '\0') {
932			svcerr_noprog(transp);
933			goto error;
934		} else {
935			free((void *) uaddr);
936		}
937	}
938	nconf = rpcbind_get_conf(transp->xp_netid);
939	if (nconf == (struct netconfig *)NULL) {
940		if (reply_type == RPCBPROC_INDIRECT)
941			svcerr_systemerr(transp);
942		if (debugging)
943			fprintf(stderr,
944			"rpcbproc_callit_com:  rpcbind_get_conf failed\n");
945		goto error;
946	}
947	ma.c_uaddr = taddr2uaddr(nconf, caller);
948	ma.s_uaddr = rbl->rpcb_map.r_addr;
949	/*
950	 *	A mergeaddr operation allocates a string, which it stores in
951	 *	ma.m_uaddr.  It's passed to forward_register() and is
952	 *	eventually freed by free_slot_*().
953	 */
954
955	stat = netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma);
956	free((void *) ma.c_uaddr);
957	if (stat)
958		(void) syslog(LOG_ERR, "netdir_merge failed for %s: %s",
959			nconf->nc_netid, netdir_sperror());
960#ifdef ND_DEBUG
961fprintf(stderr,
962"rpcbproc_callit_com: s_uaddr = %s, c_uaddr = %s, merged m_uaddr = %s\n",
963				ma.s_uaddr, ma.c_uaddr, ma.m_uaddr);
964#endif
965	if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
966		if (reply_type == RPCBPROC_INDIRECT)
967			svcerr_systemerr(transp);
968		free((void *) ma.m_uaddr);
969		ma.m_uaddr = NULL;
970		goto error;
971	}
972	bd = get_svc_dg_data(transp);
973	call_msg.rm_xid = forward_register(bd->su_xid,
974			caller, fd, ma.m_uaddr, reply_type, versnum);
975	if (call_msg.rm_xid == 0) {
976		/*
977		 * A duplicate request for the slow server.  Let's not
978		 * beat on it any more.
979		 */
980		if (debugging)
981			fprintf(stderr,
982			"rpcbproc_callit_com:  duplicate request\n");
983		free((void *) ma.m_uaddr);
984		ma.m_uaddr = NULL;
985		goto error;
986	} else 	if (call_msg.rm_xid == (uint32_t)-1) {
987		/*  forward_register failed.  Perhaps no memory. */
988		if (debugging)
989			fprintf(stderr,
990			"rpcbproc_callit_com:  forward_register failed\n");
991		free((void *) ma.m_uaddr);
992		ma.m_uaddr = NULL;
993		goto error;
994	}
995
996#ifdef DEBUG_RMTCALL
997	fprintf(stderr,
998		"rpcbproc_callit_com:  original XID %x, new XID %x\n",
999			bd->su_xid, call_msg.rm_xid);
1000#endif
1001	call_msg.rm_direction = CALL;
1002	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
1003	call_msg.rm_call.cb_prog = a.rmt_prog;
1004	call_msg.rm_call.cb_vers = a.rmt_vers;
1005	if (sendsz > RPC_BUF_MAX) {
1006#ifdef	notyet
1007		outbuf_alloc = alloca(sendsz);	/* not in IDR2? */
1008#else
1009		outbuf_alloc = malloc(sendsz);
1010#endif	/* notyet */
1011		if (outbuf_alloc == NULL) {
1012			if (reply_type == RPCBPROC_INDIRECT)
1013				svcerr_systemerr(transp);
1014			if (debugging)
1015				fprintf(stderr,
1016				"rpcbproc_callit_com:  No memory!\n");
1017			goto error;
1018		}
1019		xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
1020	} else {
1021		xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
1022	}
1023	if (!xdr_callhdr(&outxdr, &call_msg)) {
1024		if (reply_type == RPCBPROC_INDIRECT)
1025			svcerr_systemerr(transp);
1026		if (debugging)
1027			fprintf(stderr,
1028			"rpcbproc_callit_com:  xdr_callhdr failed\n");
1029		goto error;
1030	}
1031	if (!xdr_u_long(&outxdr, &(a.rmt_proc))) {
1032		if (reply_type == RPCBPROC_INDIRECT)
1033			svcerr_systemerr(transp);
1034		if (debugging)
1035			fprintf(stderr,
1036			"rpcbproc_callit_com:  xdr_u_long failed\n");
1037		goto error;
1038	}
1039
1040	if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
1041		auth = authnone_create();
1042	} else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
1043		struct authsys_parms *au;
1044
1045		au = (struct authsys_parms *)rqstp->rq_clntcred;
1046		auth = authsys_create(au->aup_machname,
1047				au->aup_uid, au->aup_gid,
1048				au->aup_len, au->aup_gids);
1049		if (auth == NULL) /* fall back */
1050			auth = authnone_create();
1051	} else {
1052		/* we do not support any other authentication scheme */
1053		if (debugging)
1054			fprintf(stderr,
1055"rpcbproc_callit_com:  oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
1056		if (reply_type == RPCBPROC_INDIRECT)
1057			svcerr_weakauth(transp); /* XXX too strong.. */
1058		goto error;
1059	}
1060	if (auth == NULL) {
1061		if (reply_type == RPCBPROC_INDIRECT)
1062			svcerr_systemerr(transp);
1063		if (debugging)
1064			fprintf(stderr,
1065		"rpcbproc_callit_com:  authwhatever_create returned NULL\n");
1066		goto error;
1067	}
1068	if (!AUTH_MARSHALL(auth, &outxdr)) {
1069		if (reply_type == RPCBPROC_INDIRECT)
1070			svcerr_systemerr(transp);
1071		AUTH_DESTROY(auth);
1072		if (debugging)
1073			fprintf(stderr,
1074		"rpcbproc_callit_com:  AUTH_MARSHALL failed\n");
1075		goto error;
1076	}
1077	AUTH_DESTROY(auth);
1078	if (!xdr_opaque_parms(&outxdr, &a)) {
1079		if (reply_type == RPCBPROC_INDIRECT)
1080			svcerr_systemerr(transp);
1081		if (debugging)
1082			fprintf(stderr,
1083		"rpcbproc_callit_com:  xdr_opaque_parms failed\n");
1084		goto error;
1085	}
1086	outlen = (int)XDR_GETPOS(&outxdr);
1087	if (outbuf_alloc)
1088		tu_data.udata.buf = outbuf_alloc;
1089	else
1090		tu_data.udata.buf = outbuf;
1091	tu_data.udata.len = outlen;
1092	tu_data.opt.len = 0;
1093
1094	na = uaddr2taddr(nconf, ma.m_uaddr);
1095	if (!na) {
1096		if (reply_type == RPCBPROC_INDIRECT)
1097			svcerr_systemerr(transp);
1098		goto error;
1099	}
1100	tu_data.addr = *na;
1101
1102	if (t_sndudata(fd, &tu_data) == -1) {
1103		if (debugging)
1104			fprintf(stderr,
1105	"rpcbproc_callit_com:  t_sndudata failed:  t_errno %d, errno %d\n",
1106				t_errno, errno);
1107		if (reply_type == RPCBPROC_INDIRECT)
1108			svcerr_systemerr(transp);
1109		goto error;
1110	}
1111	goto out;
1112
1113error:
1114	if ((call_msg.rm_xid != 0) && (ma.m_uaddr != NULL))
1115		(void) free_slot_by_xid(call_msg.rm_xid, ma.m_uaddr);
1116out:
1117	if (buf_alloc)
1118		free((void *) buf_alloc);
1119	if (outbuf_alloc)
1120		free((void *) outbuf_alloc);
1121	if (na)
1122		netdir_free((char *)na, ND_ADDR);
1123}
1124
1125#define	NFORWARD	64
1126#define	MAXTIME_OFF	300	/* 5 minutes */
1127
1128struct finfo {
1129	int		flag;
1130#define	FINFO_ACTIVE	0x1
1131	ulong_t		caller_xid;
1132	struct netbuf	*caller_addr;
1133	ulong_t		forward_xid;
1134	int		forward_fd;
1135	char		*uaddr;
1136	ulong_t		reply_type;
1137	ulong_t		versnum;
1138	time_t		time;
1139};
1140static struct finfo	FINFO[NFORWARD];
1141/*
1142 * Makes an entry into the FIFO for the given request.
1143 * If duplicate request, returns a 0, else returns the xid of its call.
1144 */
1145static ulong_t
1146forward_register(caller_xid, caller_addr, forward_fd, uaddr,
1147	reply_type, versnum)
1148	ulong_t		caller_xid;
1149	struct netbuf	*caller_addr;
1150	int		forward_fd;
1151	char		*uaddr;
1152	ulong_t		reply_type;
1153	ulong_t		versnum;
1154{
1155	int		i;
1156	int		j = 0;
1157	time_t		min_time, time_now;
1158	static ulong_t	lastxid;
1159	int		entry = -1;
1160
1161	min_time = FINFO[0].time;
1162	time_now = time((time_t *)0);
1163	/*
1164	 * initialization: once this has happened, lastxid will
1165	 * - always be a multiple of NFORWARD (which has to be a power of 2),
1166	 * - never be 0 again,
1167	 * - never be (ulong_t)(-NFORWARD)
1168	 * when entering or returning from this function.
1169	 */
1170	if (lastxid == 0) {
1171		lastxid = time_now * NFORWARD;
1172		/*
1173		 * avoid lastxid wraparound to 0,
1174		 *  and generating a forward_xid of -1
1175		 */
1176		if (lastxid >= (ulong_t)(-NFORWARD))
1177			lastxid = NFORWARD;
1178	}
1179
1180	/*
1181	 * Check if it is an duplicate entry. Then,
1182	 * try to find an empty slot.  If not available, then
1183	 * use the slot with the earliest time.
1184	 */
1185	for (i = 0; i < NFORWARD; i++) {
1186		if (FINFO[i].flag & FINFO_ACTIVE) {
1187			if ((FINFO[i].caller_xid == caller_xid) &&
1188			    (FINFO[i].reply_type == reply_type) &&
1189			    (FINFO[i].versnum == versnum) &&
1190			    (!netbufcmp(FINFO[i].caller_addr,
1191					    caller_addr))) {
1192				FINFO[i].time = time((time_t *)0);
1193				return (0);	/* Duplicate entry */
1194			} else {
1195				/* Should we wait any longer */
1196				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
1197					(void) free_slot_by_index(i);
1198			}
1199		}
1200		if (entry == -1) {
1201			if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
1202				entry = i;
1203			} else if (FINFO[i].time < min_time) {
1204				j = i;
1205				min_time = FINFO[i].time;
1206			}
1207		}
1208	}
1209	if (entry != -1) {
1210		/* use this empty slot */
1211		j = entry;
1212	} else {
1213		(void) free_slot_by_index(j);
1214	}
1215	if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
1216		return ((ulong_t)-1);
1217	}
1218	rpcb_rmtcalls++;	/* no of pending calls */
1219	FINFO[j].flag = FINFO_ACTIVE;
1220	FINFO[j].reply_type = reply_type;
1221	FINFO[j].versnum = versnum;
1222	FINFO[j].time = time_now;
1223	FINFO[j].caller_xid = caller_xid;
1224	FINFO[j].forward_fd = forward_fd;
1225	/*
1226	 * Though uaddr is not allocated here, it will still be freed
1227	 * from free_slot_*().
1228	 */
1229	FINFO[j].uaddr = uaddr;
1230	lastxid = lastxid + NFORWARD;
1231	/* avoid lastxid wraparound to 0, and generating a forward_xid of -1 */
1232	if (lastxid >= (ulong_t)(-NFORWARD))
1233		lastxid = NFORWARD;
1234
1235	FINFO[j].forward_xid = lastxid + j;	/* encode slot */
1236	return (FINFO[j].forward_xid);		/* forward on this xid */
1237}
1238
1239static struct finfo *
1240forward_find(reply_xid, uaddr)
1241	ulong_t		reply_xid;
1242	char		*uaddr;
1243{
1244	int		i;
1245
1246	i = reply_xid % NFORWARD;
1247	if (i < 0)
1248		i += NFORWARD;
1249	if ((FINFO[i].flag & FINFO_ACTIVE) &&
1250	    (strcmp(FINFO[i].uaddr, uaddr) == 0) &&
1251	    (FINFO[i].forward_xid == reply_xid)) {
1252		return (&FINFO[i]);
1253	}
1254	return (NULL);
1255}
1256
1257static int
1258free_slot_by_xid(xid, uaddr)
1259	ulong_t xid;
1260	char   *uaddr;
1261{
1262	int entry;
1263
1264	if (forward_find(xid, uaddr)) {
1265		entry = xid % NFORWARD;
1266		if (entry < 0)
1267			entry += NFORWARD;
1268		return (free_slot_by_index(entry));
1269	}
1270	return (0);
1271}
1272
1273static int
1274free_slot_by_index(index)
1275	int index;
1276{
1277	struct finfo	*fi;
1278
1279	fi = &FINFO[index];
1280	if (fi->flag & FINFO_ACTIVE) {
1281		netbuffree(fi->caller_addr);
1282		free((void *) fi->uaddr);
1283		fi->flag &= ~FINFO_ACTIVE;
1284		rpcb_rmtcalls--;
1285		return (1);
1286	}
1287	return (0);
1288}
1289
1290static int
1291netbufcmp(n1, n2)
1292	struct netbuf	*n1, *n2;
1293{
1294	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1295}
1296
1297static struct netbuf *
1298netbufdup(ap)
1299	register struct netbuf  *ap;
1300{
1301	register struct netbuf  *np;
1302
1303	np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
1304	if (np) {
1305		np->maxlen = np->len = ap->len;
1306		np->buf = ((char *)np) + sizeof (struct netbuf);
1307		(void) memcpy(np->buf, ap->buf, ap->len);
1308	}
1309	return (np);
1310}
1311
1312static void
1313netbuffree(ap)
1314	register struct netbuf  *ap;
1315{
1316	free((void *) ap);
1317}
1318
1319/*
1320 * active_fd is used to determine whether an entry in svc_pollfd is:
1321 *    1. not a forward fd (should be polled)
1322 *    2. an active forward fd (should be polled)
1323 *    3. an inactive forward fd (should not be polled)
1324 */
1325static bool_t
1326active_fd(fd)
1327	int fd;
1328{
1329	int i;
1330	time_t time_now;
1331
1332	if (find_rmtcallxprt_by_fd(fd) == (SVCXPRT *)NULL)
1333		return (TRUE);
1334	if (rpcb_rmtcalls == 0)
1335		return (FALSE);
1336	time_now = time((time_t *)0);
1337	for (i = 0; i < NFORWARD; i++)
1338		if (FINFO[i].forward_fd == fd) {
1339			if (FINFO[i].flag & FINFO_ACTIVE) {
1340			/* Should we wait any longer */
1341				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
1342					(void) free_slot_by_index(i);
1343				else
1344					return (TRUE);
1345			}
1346		}
1347	return (FALSE);
1348}
1349
1350#define	MASKVAL	(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
1351
1352void
1353my_svc_run()
1354{
1355	size_t nfds;
1356	struct pollfd pollfds[FD_SETSIZE];
1357	int poll_ret, check_ret;
1358#ifdef SVC_RUN_DEBUG
1359	int i;
1360#endif
1361	register struct pollfd	*p;
1362
1363	for (;;) {
1364		{
1365			register pollfd_t *in;
1366			register int n;		/* loop counter */
1367
1368			/*
1369			 * compress the sparse svc_pollfd strcutre
1370			 * into pollfds
1371			 */
1372			memset(pollfds, 0, sizeof (pollfds));
1373			p = pollfds;
1374			for (in = svc_pollfd, n = 0; n < svc_max_pollfd;
1375			    n++, in++) {
1376				if ((in->fd >= 0) && active_fd(in->fd)) {
1377					p->fd = in->fd;
1378					p->events = MASKVAL;
1379					p->revents = 0;
1380					p++;
1381				}
1382			}
1383			nfds = p - pollfds;
1384		}
1385		poll_ret = 0;
1386#ifdef SVC_RUN_DEBUG
1387		if (debugging) {
1388			fprintf(stderr, "polling for read on fd < ");
1389			for (i = 0, p = pollfds; i < nfds; i++, p++)
1390				if (p->events)
1391					fprintf(stderr, "%d ", p->fd);
1392			fprintf(stderr, ">\n");
1393		}
1394#endif
1395		switch (poll_ret = poll(pollfds, nfds, INFTIM)) {
1396		case -1:
1397			/*
1398			 * We ignore all errors, continuing with the assumption
1399			 * that it was set by the signal handlers (or any
1400			 * other outside event) and not caused by poll().
1401			 * If it was our refresh signal, call the refresh
1402			 * function.
1403			 */
1404			if (sigrefresh) {
1405				sigrefresh = 0;
1406				rpcb_check_init();
1407			}
1408		case 0:
1409			continue;
1410		default:
1411#ifdef SVC_RUN_DEBUG
1412			if (debugging) {
1413				fprintf(stderr, "poll returned read fds < ");
1414				for (i = 0, p = pollfds; i < nfds; i++, p++)
1415					if (p->revents)
1416						fprintf(stderr, "%d ", p->fd);
1417				fprintf(stderr, ">\n");
1418			}
1419#endif
1420			/*
1421			 * If we found as many replies on callback fds
1422			 * as the number of descriptors selectable which
1423			 * poll() returned, there can be no more so we
1424			 * don't call svc_getreq_poll.  Otherwise, there
1425			 * must be another so we must call svc_getreq_poll.
1426			 */
1427			if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
1428			    poll_ret)
1429				continue;
1430			svc_getreq_poll(pollfds, poll_ret-check_ret);
1431		}
1432	}
1433}
1434
1435static int
1436check_rmtcalls(pfds, nfds)
1437	struct pollfd *pfds;
1438	int nfds;
1439{
1440	int j, ncallbacks_found = 0;
1441	SVCXPRT *xprt;
1442
1443	/*
1444	 * This fd will not be polled if rpcb_rmtcalls == 0
1445	 */
1446	if (rpcb_rmtcalls == 0)
1447		return (0);
1448
1449	for (j = 0; j < nfds; j++) {
1450		if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
1451			if (pfds[j].revents) {
1452				ncallbacks_found++;
1453#ifdef DEBUG_RMTCALL
1454			if (debugging)
1455				fprintf(stderr,
1456"my_svc_run:  polled on forwarding fd %d, netid %s - calling handle_reply\n",
1457		pfds[j].fd, xprt->xp_netid);
1458#endif
1459				handle_reply(pfds[j].fd, xprt);
1460				pfds[j].revents = 0;
1461			}
1462		}
1463	}
1464	return (ncallbacks_found);
1465}
1466
1467static void
1468xprt_set_caller(xprt, fi)
1469	SVCXPRT *xprt;
1470	struct finfo *fi;
1471{
1472	struct svc_dg_data *bd;
1473
1474	*(svc_getrpccaller(xprt)) = *(fi->caller_addr);
1475	bd = get_svc_dg_data(xprt);
1476	bd->su_xid = fi->caller_xid;	/* set xid on reply */
1477}
1478
1479/*
1480 * Call svcerr_systemerr() only if RPCBVERS4
1481 */
1482static void
1483send_svcsyserr(xprt, fi)
1484	SVCXPRT *xprt;
1485	struct finfo	*fi;
1486{
1487	if (fi->reply_type == RPCBPROC_INDIRECT) {
1488		xprt_set_caller(xprt, fi);
1489		svcerr_systemerr(xprt);
1490	}
1491}
1492
1493static void
1494handle_reply(fd, xprt)
1495	int	fd;
1496	SVCXPRT *xprt;
1497{
1498	XDR		reply_xdrs;
1499	struct rpc_msg	reply_msg;
1500	struct rpc_err	reply_error;
1501	char		*buffer;
1502	struct finfo	*fi = NULL;
1503	int		inlen, pos, len, res, i;
1504	struct r_rmtcall_args a;
1505	struct t_unitdata	*tr_data = NULL, *tu_data;
1506	struct netconfig	*nconf = NULL;
1507	char *uaddr = NULL;
1508
1509	nconf = rpcbind_get_conf(xprt->xp_netid);
1510	if (nconf == NULL) {
1511#ifdef SVC_RUN_DEBUG
1512		if (debugging)
1513			fprintf(stderr, "handle_reply:  null xp_netid\n");
1514#endif
1515		goto done;
1516	}
1517	/*
1518	 * If this fd is not active on the forward list, ignore it
1519	 * If the svc_pollfd structure has multiple settings
1520	 * of the same fd, then it will enter handle_reply() for the first one,
1521	 * set FINFO_ACTIVE false and then get another call to handle_reply()
1522	 * with the same, now inactive, fd.
1523	 */
1524
1525	for (i = 0; i < NFORWARD; i++) {
1526		if ((FINFO[i].forward_fd == fd) &&
1527			(FINFO[i].flag & FINFO_ACTIVE))
1528				break;
1529	}
1530
1531	if (i == NFORWARD) {
1532#ifdef  SVC_RUN_DEBUG
1533		if (debugging) {
1534			fprintf(stderr, "Unsolicited message on rmtcall fd\n");
1535		}
1536#endif
1537		return;
1538	}
1539
1540	reply_msg.rm_xid = 0;  /* for easier error handling */
1541	tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
1542						T_ADDR | T_UDATA);
1543	if (tr_data == (struct t_unitdata *)NULL) {
1544		if (debugging)
1545			fprintf(stderr,
1546			"handle_reply:  t_alloc T_UNITDATA failed\n");
1547		goto done;
1548	}
1549	do {
1550		int	moreflag;
1551
1552		moreflag = 0;
1553		if (errno == EINTR)
1554			errno = 0;
1555		res = t_rcvudata(fd, tr_data, &moreflag);
1556		if (moreflag & T_MORE) {
1557			/* Drop this packet - we have no more space. */
1558			if (debugging)
1559				fprintf(stderr,
1560			"handle_reply:  recvd packet with T_MORE flag set\n");
1561			goto done;
1562		}
1563	} while (res < 0 && (t_errno == TSYSERR && errno == EINTR));
1564	if (res < 0) {
1565		if (t_errno == TLOOK) {
1566			if (debugging)
1567				fprintf(stderr,
1568	"handle_reply:  t_rcvudata returned %d, t_errno TLOOK\n", res);
1569			(void) t_rcvuderr(fd, (struct t_uderr *)NULL);
1570		}
1571
1572		if (debugging)
1573			fprintf(stderr,
1574	"handle_reply:  t_rcvudata returned %d, t_errno %d, errno %d\n",
1575				res, t_errno, errno);
1576
1577		goto done;
1578	}
1579
1580	inlen = tr_data->udata.len;
1581	uaddr = taddr2uaddr(nconf, &tr_data->addr);
1582	if (uaddr == NULL)
1583		goto done;
1584
1585#ifdef	DEBUG_MORE
1586	if (debugging)
1587		fprintf(stderr,
1588		"handle_reply:  t_rcvudata received %d-byte packet from %s\n",
1589		inlen, uaddr);
1590#endif
1591	buffer = tr_data->udata.buf;
1592	if (buffer == (char *)NULL) {
1593		goto done;
1594	}
1595	reply_msg.acpted_rply.ar_verf = _null_auth;
1596	reply_msg.acpted_rply.ar_results.where = 0;
1597	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
1598
1599	xdrmem_create(&reply_xdrs, buffer, (uint_t)inlen, XDR_DECODE);
1600	if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
1601		if (debugging)
1602			(void) fprintf(stderr,
1603				"handle_reply:  xdr_replymsg failed\n");
1604		goto done;
1605	}
1606	fi = forward_find((ulong_t)reply_msg.rm_xid, uaddr);
1607	if (fi == NULL)
1608		goto done;
1609#ifdef	SVC_RUN_DEBUG
1610	if (debugging) {
1611		fprintf(stderr, "handle_reply:  reply xid: %d fi addr: %x\n",
1612			reply_msg.rm_xid, fi);
1613	}
1614#endif
1615	__seterr_reply(&reply_msg, &reply_error);
1616	if (reply_error.re_status != RPC_SUCCESS) {
1617		if (debugging)
1618			(void) fprintf(stderr, "handle_reply:  %s\n",
1619				clnt_sperrno(reply_error.re_status));
1620		send_svcsyserr(xprt, fi);
1621		goto done;
1622	}
1623	pos = XDR_GETPOS(&reply_xdrs);
1624	len = inlen - pos;
1625	a.rmt_args.args = &buffer[pos];
1626	a.rmt_args.arglen = len;
1627	a.rmt_uaddr = fi->uaddr;
1628	a.rmt_localvers = fi->versnum;
1629
1630	xprt_set_caller(xprt, fi);
1631	/* XXX hack */
1632	tu_data =  &(get_svc_dg_data(xprt)->su_tudata);
1633
1634	tu_data->addr = xprt->xp_rtaddr;
1635#ifdef	SVC_RUN_DEBUG
1636	if (uaddr)
1637		free((void *) uaddr);
1638	uaddr = taddr2uaddr(nconf, svc_getrpccaller(xprt));
1639	if (debugging) {
1640		fprintf(stderr, "handle_reply:  forwarding address %s to %s\n",
1641			a.rmt_uaddr, uaddr ? uaddr : "unknown");
1642	}
1643#endif
1644	svc_sendreply(xprt, (xdrproc_t)xdr_rmtcall_result, (char *)&a);
1645done:
1646	if (uaddr)
1647		free((void *) uaddr);
1648	if (tr_data)
1649		t_free((char *)tr_data, T_UNITDATA);
1650	if ((fi == NULL) || (reply_msg.rm_xid == 0)) {
1651#ifdef	SVC_RUN_DEBUG
1652	if (debugging) {
1653		fprintf(stderr, "handle_reply:  NULL xid on exit!\n");
1654	}
1655#endif
1656	} else
1657		(void) free_slot_by_xid((ulong_t)reply_msg.rm_xid, fi->uaddr);
1658}
1659
1660static void
1661find_versions(prog, netid, lowvp, highvp)
1662	ulong_t prog;	/* Program Number */
1663	char *netid;	/* Transport Provider token */
1664	ulong_t *lowvp;  /* Low version number */
1665	ulong_t *highvp; /* High version number */
1666{
1667	register rpcblist_ptr rbl;
1668	int lowv = 0;
1669	int highv = 0;
1670
1671	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1672		if ((rbl->rpcb_map.r_prog != prog) ||
1673		    ((rbl->rpcb_map.r_netid != NULL) &&
1674			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1675			continue;
1676		if (lowv == 0) {
1677			highv = rbl->rpcb_map.r_vers;
1678			lowv = highv;
1679		} else if (rbl->rpcb_map.r_vers < lowv) {
1680			lowv = rbl->rpcb_map.r_vers;
1681		} else if (rbl->rpcb_map.r_vers > highv) {
1682			highv = rbl->rpcb_map.r_vers;
1683		}
1684	}
1685	*lowvp = lowv;
1686	*highvp = highv;
1687}
1688
1689/*
1690 * returns the item with the given program, version number and netid.
1691 * If that version number is not found, it returns the item with that
1692 * program number, so that address is now returned to the caller. The
1693 * caller when makes a call to this program, version number, the call
1694 * will fail and it will return with PROGVERS_MISMATCH. The user can
1695 * then determine the highest and the lowest version number for this
1696 * program using clnt_geterr() and use those program version numbers.
1697 *
1698 * Returns the RPCBLIST for the given prog, vers and netid
1699 */
1700static rpcblist_ptr
1701find_service(prog, vers, netid)
1702	ulong_t prog;	/* Program Number */
1703	ulong_t vers;	/* Version Number */
1704	char *netid;	/* Transport Provider token */
1705{
1706	register rpcblist_ptr hit = NULL;
1707	register rpcblist_ptr rbl;
1708
1709	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1710		if ((rbl->rpcb_map.r_prog != prog) ||
1711		    ((rbl->rpcb_map.r_netid != NULL) &&
1712			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1713			continue;
1714		hit = rbl;
1715		if (rbl->rpcb_map.r_vers == vers)
1716			break;
1717	}
1718	return (hit);
1719}
1720
1721/*
1722 * If the caller is from our zone and we know
1723 * who it is, we return the uid.
1724 */
1725uid_t
1726rpcb_caller_uid(SVCXPRT *transp)
1727{
1728	ucred_t *uc = alloca(ucred_size());
1729	static zoneid_t myzone = MIN_ZONEID - 1;
1730	uid_t uid;
1731
1732	if (myzone == MIN_ZONEID - 1)
1733		myzone = getzoneid();
1734
1735	if (svc_getcallerucred(transp, &uc) != 0 ||
1736	    (ucred_getzoneid(uc)) != myzone) {
1737		return (-1);
1738	} else {
1739		return (ucred_geteuid(uc));
1740	}
1741}
1742
1743/*
1744 * Copies the name associated with the uid of the caller and returns
1745 * a pointer to it.  Similar to getwd().
1746 */
1747char *
1748getowner(transp, owner)
1749	SVCXPRT *transp;
1750	char *owner;
1751{
1752	uid_t uid = rpcb_caller_uid(transp);
1753
1754	switch (uid) {
1755	case -1:
1756		return (strcpy(owner, "unknown"));
1757	case 0:
1758		return (strcpy(owner, "superuser"));
1759	default:
1760		(void) sprintf(owner, "%u", uid);
1761		return (owner);
1762	}
1763}
1764
1765#ifdef PORTMAP
1766/*
1767 * Add this to the pmap list only if it is UDP or TCP.
1768 */
1769static int
1770add_pmaplist(arg)
1771	RPCB *arg;
1772{
1773	pmap pmap;
1774	pmaplist *pml;
1775	int h1, h2, h3, h4, p1, p2;
1776
1777	if (strcmp(arg->r_netid, udptrans) == 0) {
1778		/* It is UDP! */
1779		pmap.pm_prot = IPPROTO_UDP;
1780	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1781		/* It is TCP */
1782		pmap.pm_prot = IPPROTO_TCP;
1783	} else
1784		/* Not a IP protocol */
1785		return (0);
1786
1787	/* interpret the universal address for TCP/IP */
1788	if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
1789		&h1, &h2, &h3, &h4, &p1, &p2) != 6)
1790		return (0);
1791	pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1792	pmap.pm_prog = arg->r_prog;
1793	pmap.pm_vers = arg->r_vers;
1794	/*
1795	 * add to END of list
1796	 */
1797	pml = (pmaplist *) malloc((uint_t)sizeof (pmaplist));
1798	if (pml == NULL) {
1799		(void) syslog(LOG_ERR, "rpcbind: no memory!\n");
1800		return (1);
1801	}
1802	pml->pml_map = pmap;
1803	pml->pml_next = NULL;
1804	if (list_pml == NULL) {
1805		list_pml = pml;
1806	} else {
1807		pmaplist *fnd;
1808
1809		/* Attach to the end of the list */
1810		for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
1811			;
1812		fnd->pml_next = pml;
1813	}
1814	return (0);
1815}
1816
1817/*
1818 * Delete this from the pmap list only if it is UDP or TCP.
1819 */
1820int
1821del_pmaplist(RPCB *arg)
1822{
1823	register pmaplist *pml;
1824	pmaplist *prevpml, *fnd;
1825	long prot;
1826
1827	if (strcmp(arg->r_netid, udptrans) == 0) {
1828		/* It is UDP! */
1829		prot = IPPROTO_UDP;
1830	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1831		/* It is TCP */
1832		prot = IPPROTO_TCP;
1833	} else if (arg->r_netid[0] == NULL) {
1834		prot = 0;	/* Remove all occurrences */
1835	} else {
1836		/* Not a IP protocol */
1837		return (0);
1838	}
1839	for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
1840		if ((pml->pml_map.pm_prog != arg->r_prog) ||
1841		    (pml->pml_map.pm_vers != arg->r_vers) ||
1842		    (prot && (pml->pml_map.pm_prot != prot))) {
1843			/* both pml & prevpml move forwards */
1844			prevpml = pml;
1845			pml = pml->pml_next;
1846			continue;
1847		}
1848		/* found it; pml moves forward, prevpml stays */
1849		fnd = pml;
1850		pml = pml->pml_next;
1851		if (prevpml == NULL)
1852			list_pml = pml;
1853		else
1854			prevpml->pml_next = pml;
1855		free((void *) fnd);
1856	}
1857	return (0);
1858}
1859#endif /* PORTMAP */
1860