xref: /illumos-gate/usr/src/cmd/rpcbind/rpcb_svc_com.c (revision 69a119caa6570c7077699161b7c28b6ee9f8b0f4)
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 
78 static bool_t	xdr_opaque_parms();
79 char	*getowner();
80 static ulong_t	forward_register();
81 static void	handle_reply();
82 static int	netbufcmp();
83 static int	free_slot_by_xid();
84 static int	free_slot_by_index();
85 static int	check_rmtcalls();
86 static void	netbuffree();
87 static void	find_versions();
88 static struct netbuf	*netbufdup();
89 static rpcblist_ptr find_service();
90 static int	add_pmaplist(RPCB *);
91 int	del_pmaplist(RPCB *);
92 void	delete_rbl(rpcblist_ptr);
93 
94 static char *nullstring = "";
95 static int rpcb_rmtcalls;
96 
97 /*
98  * Set a mapping of program, version, netid
99  */
100 /* ARGSUSED */
101 bool_t *
102 rpcbproc_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 
124 bool_t
125 map_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 */
195 bool_t *
196 rpcbproc_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 
218 bool_t
219 map_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 
272 void
273 delete_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 
281 void
282 delete_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*/
309 char **
310 rpcbproc_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 */
378 ulong_t *
379 rpcbproc_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 */
392 struct netbuf *
393 rpcbproc_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 */
420 char **
421 rpcbproc_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  */
451 struct encap_parms {
452 	ulong_t arglen;
453 	char *args;
454 };
455 
456 static bool_t
457 xdr_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 
465 struct 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  */
478 static bool_t
479 xdr_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  */
497 static bool_t
498 xdr_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  */
532 static bool_t
533 xdr_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 
540 struct rmtcallfd_list {
541 	int fd;
542 	SVCXPRT *xprt;
543 	char *netid;
544 	struct rmtcallfd_list *next;
545 };
546 
547 static struct rmtcallfd_list *rmthead;
548 static struct rmtcallfd_list *rmttail;
549 
550 int
551 create_rmtcall_fd(nconf)
552 struct 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 
612 static int
613 find_rmtcallfd_by_netid(netid)
614 char *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 
626 static SVCXPRT *
627 find_rmtcallxprt_by_fd(fd)
628 int 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 
688 void
689 rpcbproc_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 \
833 not 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
961 fprintf(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 
1113 error:
1114 	if ((call_msg.rm_xid != 0) && (ma.m_uaddr != NULL))
1115 		(void) free_slot_by_xid(call_msg.rm_xid, ma.m_uaddr);
1116 out:
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 
1128 struct 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 };
1140 static 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  */
1145 static ulong_t
1146 forward_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 
1239 static struct finfo *
1240 forward_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 
1257 static int
1258 free_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 
1273 static int
1274 free_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 
1290 static int
1291 netbufcmp(n1, n2)
1292 	struct netbuf	*n1, *n2;
1293 {
1294 	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1295 }
1296 
1297 static struct netbuf *
1298 netbufdup(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 
1312 static void
1313 netbuffree(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  */
1325 static bool_t
1326 active_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 
1352 void
1353 my_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 
1435 static int
1436 check_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 
1467 static void
1468 xprt_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  */
1482 static void
1483 send_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 
1493 static void
1494 handle_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);
1645 done:
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 
1660 static void
1661 find_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  */
1700 static rpcblist_ptr
1701 find_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  */
1725 uid_t
1726 rpcb_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  */
1747 char *
1748 getowner(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  */
1769 static int
1770 add_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  */
1820 int
1821 del_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