153247Sarchie/*	$NetBSD: rpcb_svc_com.c,v 1.9 2002/11/08 00:16:39 fvdl Exp $	*/
253247Sarchie/*	$FreeBSD$ */
379727Sschweikh
453247Sarchie/*
553247Sarchie * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
653247Sarchie * unrestricted use provided that this legend is included on all tape
753247Sarchie * media and as a part of the software program in whole or part.  Users
853247Sarchie * may copy or modify Sun RPC without charge, but are not authorized
953247Sarchie * to license or distribute it to anyone else except as part of a product or
1053247Sarchie * program developed by the user.
1153247Sarchie *
1253247Sarchie * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1353247Sarchie * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1479727Sschweikh * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1553247Sarchie *
1653247Sarchie * Sun RPC is provided with no support and without any obligation on the
1753247Sarchie * part of Sun Microsystems, Inc. to assist in its use, correction,
1853247Sarchie * modification or enhancement.
1953247Sarchie *
2053247Sarchie * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2153247Sarchie * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2253247Sarchie * OR ANY PART THEREOF.
2353247Sarchie *
2453247Sarchie * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2553247Sarchie * or profits or other special, indirect and consequential damages, even if
2653247Sarchie * Sun has been advised of the possibility of such damages.
2753247Sarchie *
2853247Sarchie * Sun Microsystems, Inc.
2953247Sarchie * 2550 Garcia Avenue
3053247Sarchie * Mountain View, California  94043
3153247Sarchie */
3279727Sschweikh/*
3367627Sasmodai * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
3453247Sarchie */
3553247Sarchie
3653247Sarchie/* #ident	"@(#)rpcb_svc_com.c	1.18	94/05/02 SMI" */
37236596Seadler
3859982Sarchie/*
3979538Sru * rpcb_svc_com.c
4053247Sarchie * The commom server procedure for the rpcbind.
4153247Sarchie */
4253247Sarchie
4353247Sarchie#include <sys/types.h>
44141350Sru#include <sys/stat.h>
4584306Sru#include <sys/param.h>
4653247Sarchie#include <sys/poll.h>
4753247Sarchie#include <sys/socket.h>
4853247Sarchie#include <rpc/rpc.h>
4981622Sru#include <rpc/rpcb_prot.h>
5081622Sru#include <rpc/svc_dg.h>
51117011Sru#include <netconfig.h>
52117011Sru#include <errno.h>
5354927Sjulian#include <syslog.h>
5453247Sarchie#include <unistd.h>
55117011Sru#include <stdio.h>
56117011Sru#ifdef PORTMAP
5754927Sjulian#include <netinet/in.h>
5853247Sarchie#include <rpc/pmap_prot.h>
5959982Sarchie#endif /* PORTMAP */
6053247Sarchie#include <string.h>
6153939Sarchie#include <stdlib.h>
6253939Sarchie
6354927Sjulian#include "rpcbind.h"
6453247Sarchie
6553939Sarchie#define RPC_BUF_MAX	65536	/* can be raised if required */
6653247Sarchie
6753247Sarchiestatic char *nullstring = "";
6854927Sjulianstatic int rpcb_rmtcalls;
69117011Sru
70117011Srustruct rmtcallfd_list {
71117011Sru	int fd;
72117011Sru	SVCXPRT *xprt;
7353939Sarchie	char *netid;
7453247Sarchie	struct rmtcallfd_list *next;
7553247Sarchie};
7653247Sarchie
7753247Sarchie#define NFORWARD        64
7853247Sarchie#define MAXTIME_OFF     300     /* 5 minutes */
7973233Sru
8053247Sarchiestruct finfo {
8173233Sru	int             flag;
8273233Sru#define FINFO_ACTIVE    0x1
8353247Sarchie	u_int32_t       caller_xid;
8473233Sru        struct netbuf   *caller_addr;
8553247Sarchie	u_int32_t       forward_xid;
8653247Sarchie	int             forward_fd;
8753247Sarchie	char            *uaddr;
88131530Sru	rpcproc_t       reply_type;
89131530Sru	rpcvers_t       versnum;
9053247Sarchie	time_t          time;
9179727Sschweikh};
9253247Sarchiestatic struct finfo     FINFO[NFORWARD];
93131108Sjulian
94131108Sjulian
95131108Sjulianstatic bool_t xdr_encap_parms(XDR *, struct encap_parms *);
96131108Sjulianstatic bool_t xdr_rmtcall_args(XDR *, struct r_rmtcall_args *);
97131108Sjulianstatic bool_t xdr_rmtcall_result(XDR *, struct r_rmtcall_args *);
98131108Sjulianstatic bool_t xdr_opaque_parms(XDR *, struct r_rmtcall_args *);
99131108Sjulianstatic int find_rmtcallfd_by_netid(char *);
100131530Srustatic SVCXPRT *find_rmtcallxprt_by_fd(int);
101131108Sjulianstatic int forward_register(u_int32_t, struct netbuf *, int, char *,
102131108Sjulian    rpcproc_t, rpcvers_t, u_int32_t *);
103131108Sjulianstatic struct finfo *forward_find(u_int32_t);
104131108Sjulianstatic int free_slot_by_xid(u_int32_t);
105131108Sjulianstatic int free_slot_by_index(int);
106131108Sjulianstatic int netbufcmp(struct netbuf *, struct netbuf *);
107131108Sjulianstatic struct netbuf *netbufdup(struct netbuf *);
108131108Sjulianstatic void netbuffree(struct netbuf *);
109131530Srustatic int check_rmtcalls(struct pollfd *, int);
110131108Sjulianstatic void xprt_set_caller(SVCXPRT *, struct finfo *);
11153247Sarchiestatic void send_svcsyserr(SVCXPRT *, struct finfo *);
11253247Sarchiestatic void handle_reply(int, SVCXPRT *);
11353247Sarchiestatic void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
114242997Sjoelstatic rpcblist_ptr find_service(rpcprog_t, rpcvers_t, char *);
11553247Sarchiestatic char *getowner(SVCXPRT *, char *, size_t);
11653247Sarchiestatic int add_pmaplist(RPCB *);
117117011Srustatic int del_pmaplist(RPCB *);
118117011Sru
119131530Sru/*
12053247Sarchie * Set a mapping of program, version, netid
121242997Sjoel */
12253247Sarchie/* ARGSUSED */
12353247Sarchievoid *
124117011Srurpcbproc_set_com(void *arg, struct svc_req *rqstp __unused, SVCXPRT *transp,
125117011Sru		 rpcvers_t rpcbversnum)
12653247Sarchie{
12753247Sarchie	RPCB *regp = (RPCB *)arg;
128242997Sjoel	static bool_t ans;
12953247Sarchie	char owner[64];
13053247Sarchie
131117011Sru#ifdef RPCBIND_DEBUG
132117011Sru	if (debugging)
133131530Sru		fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
13453939Sarchie		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
135242997Sjoel		    regp->r_netid, regp->r_addr);
136151798Sru#endif
137151798Sru	ans = map_set(regp, getowner(transp, owner, sizeof owner));
138151798Sru#ifdef RPCBIND_DEBUG
139151798Sru	if (debugging)
140151798Sru		fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
141151798Sru#endif
142151798Sru	/* XXX: should have used some defined constant here */
143151798Sru	rpcbs_set(rpcbversnum - 2, ans);
144151798Sru	return (void *)&ans;
145151798Sru}
146151798Sru
147151798Srubool_t
148151798Srumap_set(RPCB *regp, char *owner)
149151798Sru{
150151798Sru	RPCB reg, *a;
151242997Sjoel	rpcblist_ptr rbl, fnd;
15253939Sarchie
15377973Ssobomax	reg = *regp;
154117011Sru	/*
155117011Sru	 * check to see if already used
156131530Sru	 * find_service returns a hit even if
15753939Sarchie	 * the versions don't match, so check for it
158242997Sjoel	 */
15953939Sarchie	fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
16053939Sarchie	if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
161117011Sru		if (!strcmp(fnd->rpcb_map.r_addr, reg.r_addr))
162117011Sru			/*
163131530Sru			 * if these match then it is already
16453939Sarchie			 * registered so just say "OK".
165242997Sjoel			 */
16653939Sarchie			return (TRUE);
16753939Sarchie		else
16853939Sarchie			return (FALSE);
169131530Sru	}
170242997Sjoel	/*
17153939Sarchie	 * add to the end of the list
17253939Sarchie	 */
17353939Sarchie	rbl = malloc(sizeof (RPCBLIST));
174131530Sru	if (rbl == NULL)
17553939Sarchie		return (FALSE);
17653939Sarchie	a = &(rbl->rpcb_map);
17753939Sarchie	a->r_prog = reg.r_prog;
17853939Sarchie	a->r_vers = reg.r_vers;
17953247Sarchie	a->r_netid = strdup(reg.r_netid);
18053939Sarchie	a->r_addr = strdup(reg.r_addr);
18153939Sarchie	a->r_owner = strdup(owner);
182131530Sru	if (!a->r_addr || !a->r_netid || !a->r_owner) {
18354927Sjulian		if (a->r_netid)
18454927Sjulian			free(a->r_netid);
18554927Sjulian		if (a->r_addr)
186117011Sru			free(a->r_addr);
187117011Sru		if (a->r_owner)
18853939Sarchie			free(a->r_owner);
18953939Sarchie		free(rbl);
19053939Sarchie		return (FALSE);
19153939Sarchie	}
19253939Sarchie	rbl->rpcb_next = (rpcblist_ptr)NULL;
193117011Sru	if (list_rbl == NULL) {
194117011Sru		list_rbl = rbl;
19553939Sarchie	} else {
19653939Sarchie		for (fnd = list_rbl; fnd->rpcb_next;
19753939Sarchie			fnd = fnd->rpcb_next)
19853939Sarchie			;
19953939Sarchie		fnd->rpcb_next = rbl;
20053939Sarchie	}
20153939Sarchie#ifdef PORTMAP
202229930Smelifaro	(void) add_pmaplist(regp);
20353939Sarchie#endif
20458007Sarchie	return (TRUE);
20558007Sarchie}
20653939Sarchie
20753939Sarchie/*
20858007Sarchie * Unset a mapping of program, version, netid
20953939Sarchie */
21053939Sarchie/* ARGSUSED */
21153939Sarchievoid *
212131530Srurpcbproc_unset_com(void *arg, struct svc_req *rqstp __unused, SVCXPRT *transp,
21354927Sjulian		   rpcvers_t rpcbversnum)
21454927Sjulian{
215117011Sru	RPCB *regp = (RPCB *)arg;
216117011Sru	static bool_t ans;
21753939Sarchie	char owner[64];
218229930Smelifaro
219229930Smelifaro#ifdef RPCBIND_DEBUG
220229930Smelifaro	if (debugging)
221229930Smelifaro		fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
222229930Smelifaro		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
223229930Smelifaro		    regp->r_netid);
22453247Sarchie#endif
22553247Sarchie	ans = map_unset(regp, getowner(transp, owner, sizeof owner));
22653247Sarchie#ifdef RPCBIND_DEBUG
22753247Sarchie	if (debugging)
22853247Sarchie		fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
22953247Sarchie#endif
23053247Sarchie	/* XXX: should have used some defined constant here */
23153247Sarchie	rpcbs_unset(rpcbversnum - 2, ans);
23259982Sarchie	return (void *)&ans;
233131108Sjulian}
234165282Srwatson
235165282Srwatsonbool_t
23654927Sjulianmap_unset(RPCB *regp, char *owner)
23754927Sjulian{
23854927Sjulian	int ans = 0;
23954927Sjulian	rpcblist_ptr rbl, prev, tmp;
24054927Sjulian
24154927Sjulian	if (owner == NULL)
24267627Sasmodai		return (0);
243
244	for (prev = NULL, rbl = list_rbl; rbl; /* cstyle */) {
245		if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
246			(rbl->rpcb_map.r_vers != regp->r_vers) ||
247			(regp->r_netid[0] && strcasecmp(regp->r_netid,
248				rbl->rpcb_map.r_netid))) {
249			/* both rbl & prev move forwards */
250			prev = rbl;
251			rbl = rbl->rpcb_next;
252			continue;
253		}
254		/*
255		 * Check whether appropriate uid. Unset only
256		 * if superuser or the owner itself.
257		 */
258		if (strcmp(owner, "superuser") &&
259			strcmp(rbl->rpcb_map.r_owner, owner))
260			return (0);
261		/* found it; rbl moves forward, prev stays */
262		ans = 1;
263		tmp = rbl;
264		rbl = rbl->rpcb_next;
265		if (prev == NULL)
266			list_rbl = rbl;
267		else
268			prev->rpcb_next = rbl;
269		free(tmp->rpcb_map.r_addr);
270		free(tmp->rpcb_map.r_netid);
271		free(tmp->rpcb_map.r_owner);
272		free(tmp);
273	}
274#ifdef PORTMAP
275	if (ans)
276		(void) del_pmaplist(regp);
277#endif
278	/*
279	 * We return 1 either when the entry was not there or it
280	 * was able to unset it.  It can come to this point only if
281	 * atleast one of the conditions is true.
282	 */
283	return (1);
284}
285
286void
287delete_prog(unsigned int prog)
288{
289	RPCB reg;
290	register rpcblist_ptr rbl;
291
292	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
293		if ((rbl->rpcb_map.r_prog != prog))
294			continue;
295		if (is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr))
296			continue;
297		reg.r_prog = rbl->rpcb_map.r_prog;
298		reg.r_vers = rbl->rpcb_map.r_vers;
299		reg.r_netid = strdup(rbl->rpcb_map.r_netid);
300		(void) map_unset(&reg, "superuser");
301		free(reg.r_netid);
302	}
303}
304
305void *
306rpcbproc_getaddr_com(RPCB *regp, struct svc_req *rqstp __unused,
307		     SVCXPRT *transp, rpcvers_t rpcbversnum, rpcvers_t verstype)
308{
309	static char *uaddr;
310	char *saddr = NULL;
311	rpcblist_ptr fnd;
312
313	if (uaddr != NULL && uaddr != nullstring) {
314		free(uaddr);
315		uaddr = NULL;
316	}
317	fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
318	if (fnd && ((verstype == RPCB_ALLVERS) ||
319		    (regp->r_vers == fnd->rpcb_map.r_vers))) {
320		if (*(regp->r_addr) != '\0') {  /* may contain a hint about */
321			saddr = regp->r_addr;   /* the interface that we    */
322		}				/* should use */
323		if (!(uaddr = mergeaddr(transp, transp->xp_netid,
324				fnd->rpcb_map.r_addr, saddr))) {
325			/* Try whatever we have */
326			uaddr = strdup(fnd->rpcb_map.r_addr);
327		} else if (!uaddr[0]) {
328			/*
329			 * The server died.  Unset all versions of this prog.
330			 */
331			delete_prog(regp->r_prog);
332			uaddr = nullstring;
333		}
334	} else {
335		uaddr = nullstring;
336	}
337#ifdef RPCBIND_DEBUG
338	if (debugging)
339		fprintf(stderr, "getaddr: %s\n", uaddr);
340#endif
341	/* XXX: should have used some defined constant here */
342	rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers,
343		transp->xp_netid, uaddr);
344	return (void *)&uaddr;
345}
346
347/* ARGSUSED */
348void *
349rpcbproc_gettime_com(void *arg __unused, struct svc_req *rqstp __unused,
350		     SVCXPRT *transp __unused, rpcvers_t rpcbversnum __unused)
351{
352	static time_t curtime;
353
354	(void) time(&curtime);
355	return (void *)&curtime;
356}
357
358/*
359 * Convert uaddr to taddr. Should be used only by
360 * local servers/clients. (kernel level stuff only)
361 */
362/* ARGSUSED */
363void *
364rpcbproc_uaddr2taddr_com(void *arg, struct svc_req *rqstp __unused,
365			 SVCXPRT *transp, rpcvers_t rpcbversnum __unused)
366{
367	char **uaddrp = (char **)arg;
368	struct netconfig *nconf;
369	static struct netbuf nbuf;
370	static struct netbuf *taddr;
371
372	if (taddr) {
373		free(taddr->buf);
374		free(taddr);
375		taddr = NULL;
376	}
377	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
378	    ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
379		(void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
380		return (void *)&nbuf;
381	}
382	return (void *)taddr;
383}
384
385/*
386 * Convert taddr to uaddr. Should be used only by
387 * local servers/clients. (kernel level stuff only)
388 */
389/* ARGSUSED */
390void *
391rpcbproc_taddr2uaddr_com(void *arg, struct svc_req *rqstp __unused,
392			 SVCXPRT *transp, rpcvers_t rpcbversnum __unused)
393{
394	struct netbuf *taddr = (struct netbuf *)arg;
395	static char *uaddr;
396	struct netconfig *nconf;
397
398#ifdef CHEW_FDS
399	int fd;
400
401	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
402		uaddr = (char *)strerror(errno);
403		return (&uaddr);
404	}
405#endif /* CHEW_FDS */
406	if (uaddr != NULL && uaddr != nullstring) {
407		free(uaddr);
408		uaddr = NULL;
409	}
410	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
411		((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
412		uaddr = nullstring;
413	}
414	return (void *)&uaddr;
415}
416
417
418static bool_t
419xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
420{
421	return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen), ~0));
422}
423
424/*
425 * XDR remote call arguments.  It ignores the address part.
426 * written for XDR_DECODE direction only
427 */
428static bool_t
429xdr_rmtcall_args(XDR *xdrs, struct r_rmtcall_args *cap)
430{
431	/* does not get the address or the arguments */
432	if (xdr_u_int32_t(xdrs, &(cap->rmt_prog)) &&
433	    xdr_u_int32_t(xdrs, &(cap->rmt_vers)) &&
434	    xdr_u_int32_t(xdrs, &(cap->rmt_proc))) {
435		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
436	}
437	return (FALSE);
438}
439
440/*
441 * XDR remote call results along with the address.  Ignore
442 * program number, version  number and proc number.
443 * Written for XDR_ENCODE direction only.
444 */
445static bool_t
446xdr_rmtcall_result(XDR *xdrs, struct r_rmtcall_args *cap)
447{
448	bool_t result;
449
450#ifdef PORTMAP
451	if (cap->rmt_localvers == PMAPVERS) {
452		int h1, h2, h3, h4, p1, p2;
453		u_long port;
454
455		/* interpret the universal address for TCP/IP */
456		if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
457			&h1, &h2, &h3, &h4, &p1, &p2) != 6)
458			return (FALSE);
459		port = ((p1 & 0xff) << 8) + (p2 & 0xff);
460		result = xdr_u_long(xdrs, &port);
461	} else
462#endif
463		if ((cap->rmt_localvers == RPCBVERS) ||
464		    (cap->rmt_localvers == RPCBVERS4)) {
465		result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
466	} else {
467		return (FALSE);
468	}
469	if (result == TRUE)
470		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
471	return (FALSE);
472}
473
474/*
475 * only worries about the struct encap_parms part of struct r_rmtcall_args.
476 * The arglen must already be set!!
477 */
478static bool_t
479xdr_opaque_parms(XDR *xdrs, struct r_rmtcall_args *cap)
480{
481	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
482}
483
484static struct rmtcallfd_list *rmthead;
485static struct rmtcallfd_list *rmttail;
486
487int
488create_rmtcall_fd(struct netconfig *nconf)
489{
490	int fd;
491	struct rmtcallfd_list *rmt;
492	SVCXPRT *xprt;
493
494	if ((fd = __rpc_nconf2fd(nconf)) == -1) {
495		if (debugging)
496			fprintf(stderr,
497	"create_rmtcall_fd: couldn't open \"%s\" (errno %d)\n",
498			nconf->nc_device, errno);
499		return (-1);
500	}
501	xprt = svc_tli_create(fd, 0, (struct t_bind *) 0, 0, 0);
502	if (xprt == NULL) {
503		if (debugging)
504			fprintf(stderr,
505				"create_rmtcall_fd: svc_tli_create failed\n");
506		return (-1);
507	}
508	rmt = malloc(sizeof (struct rmtcallfd_list));
509	if (rmt == NULL) {
510		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
511		return (-1);
512	}
513	rmt->xprt = xprt;
514	rmt->netid = strdup(nconf->nc_netid);
515	xprt->xp_netid = rmt->netid;
516	rmt->fd = fd;
517	rmt->next = NULL;
518	if (rmthead == NULL) {
519		rmthead = rmt;
520		rmttail = rmt;
521	} else {
522		rmttail->next = rmt;
523		rmttail = rmt;
524	}
525	/* XXX not threadsafe */
526	if (fd > svc_maxfd)
527		svc_maxfd = fd;
528	FD_SET(fd, &svc_fdset);
529	return (fd);
530}
531
532static int
533find_rmtcallfd_by_netid(char *netid)
534{
535	struct rmtcallfd_list *rmt;
536
537	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
538		if (strcmp(netid, rmt->netid) == 0) {
539			return (rmt->fd);
540		}
541	}
542	return (-1);
543}
544
545static SVCXPRT *
546find_rmtcallxprt_by_fd(int fd)
547{
548	struct rmtcallfd_list *rmt;
549
550	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
551		if (fd == rmt->fd) {
552			return (rmt->xprt);
553		}
554	}
555	return (NULL);
556}
557
558
559/*
560 * Call a remote procedure service.  This procedure is very quiet when things
561 * go wrong.  The proc is written to support broadcast rpc.  In the broadcast
562 * case, a machine should shut-up instead of complain, lest the requestor be
563 * overrun with complaints at the expense of not hearing a valid reply.
564 * When receiving a request and verifying that the service exists, we
565 *
566 *	receive the request
567 *
568 *	open a new TLI endpoint on the same transport on which we received
569 *	the original request
570 *
571 *	remember the original request's XID (which requires knowing the format
572 *	of the svc_dg_data structure)
573 *
574 *	forward the request, with a new XID, to the requested service,
575 *	remembering the XID used to send this request (for later use in
576 *	reassociating the answer with the original request), the requestor's
577 *	address, the file descriptor on which the forwarded request is
578 *	made and the service's address.
579 *
580 *	mark the file descriptor on which we anticipate receiving a reply from
581 *	the service and one to select for in our private svc_run procedure
582 *
583 * At some time in the future, a reply will be received from the service to
584 * which we forwarded the request.  At that time, we detect that the socket
585 * used was for forwarding (by looking through the finfo structures to see
586 * whether the fd corresponds to one of those) and call handle_reply() to
587 *
588 *	receive the reply
589 *
590 *	bundle the reply, along with the service's universal address
591 *
592 *	create a SVCXPRT structure and use a version of svc_sendreply
593 *	that allows us to specify the reply XID and destination, send the reply
594 *	to the original requestor.
595 */
596
597void
598rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp,
599		    rpcproc_t reply_type, rpcvers_t versnum)
600{
601	register rpcblist_ptr rbl;
602	struct netconfig *nconf;
603	struct netbuf *caller;
604	struct r_rmtcall_args a;
605	char *buf_alloc = NULL, *outbufp;
606	char *outbuf_alloc = NULL;
607	char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
608	struct netbuf *na = (struct netbuf *) NULL;
609	struct rpc_msg call_msg;
610	int outlen;
611	u_int sendsz;
612	XDR outxdr;
613	AUTH *auth;
614	int fd = -1;
615	char *uaddr, *m_uaddr = NULL, *local_uaddr = NULL;
616	u_int32_t *xidp;
617	struct __rpc_sockinfo si;
618	struct sockaddr *localsa;
619	struct netbuf tbuf;
620
621	if (!__rpc_fd2sockinfo(transp->xp_fd, &si)) {
622		if (reply_type == RPCBPROC_INDIRECT)
623			svcerr_systemerr(transp);
624		return;
625	}
626	if (si.si_socktype != SOCK_DGRAM)
627		return;	/* Only datagram type accepted */
628	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, UDPMSGSIZE);
629	if (sendsz == 0) {	/* data transfer not supported */
630		if (reply_type == RPCBPROC_INDIRECT)
631			svcerr_systemerr(transp);
632		return;
633	}
634	/*
635	 * Should be multiple of 4 for XDR.
636	 */
637	sendsz = ((sendsz + 3) / 4) * 4;
638	if (sendsz > RPC_BUF_MAX) {
639#ifdef	notyet
640		buf_alloc = alloca(sendsz);		/* not in IDR2? */
641#else
642		buf_alloc = malloc(sendsz);
643#endif	/* notyet */
644		if (buf_alloc == NULL) {
645			if (debugging)
646				fprintf(stderr,
647					"rpcbproc_callit_com:  No Memory!\n");
648			if (reply_type == RPCBPROC_INDIRECT)
649				svcerr_systemerr(transp);
650			return;
651		}
652		a.rmt_args.args = buf_alloc;
653	} else {
654		a.rmt_args.args = buf;
655	}
656
657	call_msg.rm_xid = 0;	/* For error checking purposes */
658	if (!svc_getargs(transp, (xdrproc_t) xdr_rmtcall_args, (char *) &a)) {
659		if (reply_type == RPCBPROC_INDIRECT)
660			svcerr_decode(transp);
661		if (debugging)
662			fprintf(stderr,
663			"rpcbproc_callit_com:  svc_getargs failed\n");
664		goto error;
665	}
666
667	if (!check_callit(transp, &a, versnum)) {
668		svcerr_weakauth(transp);
669		goto error;
670	}
671
672	caller = svc_getrpccaller(transp);
673#ifdef RPCBIND_DEBUG
674	if (debugging) {
675		uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
676		fprintf(stderr, "%s %s req for (%lu, %lu, %lu, %s) from %s : ",
677			versnum == PMAPVERS ? "pmap_rmtcall" :
678			versnum == RPCBVERS ? "rpcb_rmtcall" :
679			versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
680			reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
681			(unsigned long)a.rmt_prog, (unsigned long)a.rmt_vers,
682			(unsigned long)a.rmt_proc, transp->xp_netid,
683			uaddr ? uaddr : "unknown");
684		if (uaddr)
685			free(uaddr);
686	}
687#endif
688
689	rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
690
691	rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
692			a.rmt_proc, transp->xp_netid, rbl);
693
694	if (rbl == (rpcblist_ptr)NULL) {
695#ifdef RPCBIND_DEBUG
696		if (debugging)
697			fprintf(stderr, "not found\n");
698#endif
699		if (reply_type == RPCBPROC_INDIRECT)
700			svcerr_noprog(transp);
701		goto error;
702	}
703	if (rbl->rpcb_map.r_vers != a.rmt_vers) {
704		if (reply_type == RPCBPROC_INDIRECT) {
705			rpcvers_t vers_low, vers_high;
706
707			find_versions(a.rmt_prog, transp->xp_netid,
708				&vers_low, &vers_high);
709			svcerr_progvers(transp, vers_low, vers_high);
710		}
711		goto error;
712	}
713
714#ifdef RPCBIND_DEBUG
715	if (debugging)
716		fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
717#endif
718	/*
719	 *	Check whether this entry is valid and a server is present
720	 *	Mergeaddr() returns NULL if no such entry is present, and
721	 *	returns "" if the entry was present but the server is not
722	 *	present (i.e., it crashed).
723	 */
724	if (reply_type == RPCBPROC_INDIRECT) {
725		uaddr = mergeaddr(transp, transp->xp_netid,
726			rbl->rpcb_map.r_addr, NULL);
727		if (uaddr == NULL || uaddr[0] == '\0') {
728			svcerr_noprog(transp);
729			if (uaddr != NULL)
730				free(uaddr);
731			goto error;
732		}
733		free(uaddr);
734	}
735	nconf = rpcbind_get_conf(transp->xp_netid);
736	if (nconf == (struct netconfig *)NULL) {
737		if (reply_type == RPCBPROC_INDIRECT)
738			svcerr_systemerr(transp);
739		if (debugging)
740			fprintf(stderr,
741			"rpcbproc_callit_com:  rpcbind_get_conf failed\n");
742		goto error;
743	}
744	localsa = local_sa(((struct sockaddr *)caller->buf)->sa_family);
745	if (localsa == NULL) {
746		if (debugging)
747			fprintf(stderr,
748			"rpcbproc_callit_com: no local address\n");
749		goto error;
750	}
751	tbuf.len = tbuf.maxlen = localsa->sa_len;
752	tbuf.buf = localsa;
753	local_uaddr =
754	    addrmerge(&tbuf, rbl->rpcb_map.r_addr, NULL, nconf->nc_netid);
755	m_uaddr = addrmerge(caller, rbl->rpcb_map.r_addr, NULL,
756			nconf->nc_netid);
757#ifdef RPCBIND_DEBUG
758	if (debugging)
759		fprintf(stderr, "merged uaddr %s\n", m_uaddr);
760#endif
761	if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
762		if (reply_type == RPCBPROC_INDIRECT)
763			svcerr_systemerr(transp);
764		goto error;
765	}
766	xidp = __rpcb_get_dg_xidp(transp);
767	switch (forward_register(*xidp, caller, fd, m_uaddr, reply_type,
768	    versnum, &call_msg.rm_xid)) {
769	case 1:
770		/* Success; forward_register() will free m_uaddr for us. */
771		m_uaddr = NULL;
772		break;
773	case 0:
774		/*
775		 * A duplicate request for the slow server.  Let's not
776		 * beat on it any more.
777		 */
778		if (debugging)
779			fprintf(stderr,
780			"rpcbproc_callit_com:  duplicate request\n");
781		goto error;
782	case -1:
783		/*  forward_register failed.  Perhaps no memory. */
784		if (debugging)
785			fprintf(stderr,
786			"rpcbproc_callit_com:  forward_register failed\n");
787		goto error;
788	}
789
790#ifdef DEBUG_RMTCALL
791	if (debugging)
792		fprintf(stderr,
793			"rpcbproc_callit_com:  original XID %x, new XID %x\n",
794				*xidp, call_msg.rm_xid);
795#endif
796	call_msg.rm_direction = CALL;
797	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
798	call_msg.rm_call.cb_prog = a.rmt_prog;
799	call_msg.rm_call.cb_vers = a.rmt_vers;
800	if (sendsz > RPC_BUF_MAX) {
801#ifdef	notyet
802		outbuf_alloc = alloca(sendsz);	/* not in IDR2? */
803#else
804		outbuf_alloc = malloc(sendsz);
805#endif	/* notyet */
806		if (outbuf_alloc == NULL) {
807			if (reply_type == RPCBPROC_INDIRECT)
808				svcerr_systemerr(transp);
809			if (debugging)
810				fprintf(stderr,
811				"rpcbproc_callit_com:  No memory!\n");
812			goto error;
813		}
814		xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
815	} else {
816		xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
817	}
818	if (!xdr_callhdr(&outxdr, &call_msg)) {
819		if (reply_type == RPCBPROC_INDIRECT)
820			svcerr_systemerr(transp);
821		if (debugging)
822			fprintf(stderr,
823			"rpcbproc_callit_com:  xdr_callhdr failed\n");
824		goto error;
825	}
826	if (!xdr_u_int32_t(&outxdr, &(a.rmt_proc))) {
827		if (reply_type == RPCBPROC_INDIRECT)
828			svcerr_systemerr(transp);
829		if (debugging)
830			fprintf(stderr,
831			"rpcbproc_callit_com:  xdr_u_long failed\n");
832		goto error;
833	}
834
835	if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
836		auth = authnone_create();
837	} else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
838		struct authunix_parms *au;
839
840		au = (struct authunix_parms *)rqstp->rq_clntcred;
841		auth = authunix_create(au->aup_machname,
842				au->aup_uid, au->aup_gid,
843				au->aup_len, au->aup_gids);
844		if (auth == NULL) /* fall back */
845			auth = authnone_create();
846	} else {
847		/* we do not support any other authentication scheme */
848		if (debugging)
849			fprintf(stderr,
850"rpcbproc_callit_com:  oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
851		if (reply_type == RPCBPROC_INDIRECT)
852			svcerr_weakauth(transp); /* XXX too strong.. */
853		goto error;
854	}
855	if (auth == NULL) {
856		if (reply_type == RPCBPROC_INDIRECT)
857			svcerr_systemerr(transp);
858		if (debugging)
859			fprintf(stderr,
860		"rpcbproc_callit_com:  authwhatever_create returned NULL\n");
861		goto error;
862	}
863	if (!AUTH_MARSHALL(auth, &outxdr)) {
864		if (reply_type == RPCBPROC_INDIRECT)
865			svcerr_systemerr(transp);
866		AUTH_DESTROY(auth);
867		if (debugging)
868			fprintf(stderr,
869		"rpcbproc_callit_com:  AUTH_MARSHALL failed\n");
870		goto error;
871	}
872	AUTH_DESTROY(auth);
873	if (!xdr_opaque_parms(&outxdr, &a)) {
874		if (reply_type == RPCBPROC_INDIRECT)
875			svcerr_systemerr(transp);
876		if (debugging)
877			fprintf(stderr,
878		"rpcbproc_callit_com:  xdr_opaque_parms failed\n");
879		goto error;
880	}
881	outlen = (int) XDR_GETPOS(&outxdr);
882	if (outbuf_alloc)
883		outbufp = outbuf_alloc;
884	else
885		outbufp = outbuf;
886
887	na = uaddr2taddr(nconf, local_uaddr);
888	if (!na) {
889		if (reply_type == RPCBPROC_INDIRECT)
890			svcerr_systemerr(transp);
891		goto error;
892	}
893
894	if (sendto(fd, outbufp, outlen, 0, (struct sockaddr *)na->buf, na->len)
895	    != outlen) {
896		if (debugging)
897			fprintf(stderr,
898	"rpcbproc_callit_com:  sendto failed:  errno %d\n", errno);
899		if (reply_type == RPCBPROC_INDIRECT)
900			svcerr_systemerr(transp);
901		goto error;
902	}
903	goto out;
904
905error:
906	if (call_msg.rm_xid != 0)
907		(void) free_slot_by_xid(call_msg.rm_xid);
908out:
909	if (local_uaddr)
910		free(local_uaddr);
911	if (buf_alloc)
912		free(buf_alloc);
913	if (outbuf_alloc)
914		free(outbuf_alloc);
915	if (na) {
916		free(na->buf);
917		free(na);
918	}
919	if (m_uaddr != NULL)
920		free(m_uaddr);
921}
922
923/*
924 * Makes an entry into the FIFO for the given request.
925 * Returns 1 on success, 0 if this is a duplicate request, or -1 on error.
926 * *callxidp is set to the xid of the call.
927 */
928static int
929forward_register(u_int32_t caller_xid, struct netbuf *caller_addr,
930		 int forward_fd, char *uaddr, rpcproc_t reply_type,
931		 rpcvers_t versnum, u_int32_t *callxidp)
932{
933	int		i;
934	int		j = 0;
935	time_t		min_time, time_now;
936	static u_int32_t	lastxid;
937	int		entry = -1;
938
939	min_time = FINFO[0].time;
940	time_now = time((time_t *)0);
941	/* initialization */
942	if (lastxid == 0)
943		lastxid = time_now * NFORWARD;
944
945	/*
946	 * Check if it is a duplicate entry. Then,
947	 * try to find an empty slot.  If not available, then
948	 * use the slot with the earliest time.
949	 */
950	for (i = 0; i < NFORWARD; i++) {
951		if (FINFO[i].flag & FINFO_ACTIVE) {
952			if ((FINFO[i].caller_xid == caller_xid) &&
953			    (FINFO[i].reply_type == reply_type) &&
954			    (FINFO[i].versnum == versnum) &&
955			    (!netbufcmp(FINFO[i].caller_addr,
956					    caller_addr))) {
957				FINFO[i].time = time((time_t *)0);
958				return (0);	/* Duplicate entry */
959			} else {
960				/* Should we wait any longer */
961				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
962					(void) free_slot_by_index(i);
963			}
964		}
965		if (entry == -1) {
966			if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
967				entry = i;
968			} else if (FINFO[i].time < min_time) {
969				j = i;
970				min_time = FINFO[i].time;
971			}
972		}
973	}
974	if (entry != -1) {
975		/* use this empty slot */
976		j = entry;
977	} else {
978		(void) free_slot_by_index(j);
979	}
980	if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
981		return (-1);
982	}
983	rpcb_rmtcalls++;	/* no of pending calls */
984	FINFO[j].flag = FINFO_ACTIVE;
985	FINFO[j].reply_type = reply_type;
986	FINFO[j].versnum = versnum;
987	FINFO[j].time = time_now;
988	FINFO[j].caller_xid = caller_xid;
989	FINFO[j].forward_fd = forward_fd;
990	/*
991	 * Though uaddr is not allocated here, it will still be freed
992	 * from free_slot_*().
993	 */
994	FINFO[j].uaddr = uaddr;
995	lastxid = lastxid + NFORWARD;
996	/* Don't allow a zero xid below. */
997	if ((u_int32_t)(lastxid + NFORWARD) <= NFORWARD)
998		lastxid = NFORWARD;
999	FINFO[j].forward_xid = lastxid + j;	/* encode slot */
1000	*callxidp = FINFO[j].forward_xid;	/* forward on this xid */
1001	return (1);
1002}
1003
1004static struct finfo *
1005forward_find(u_int32_t reply_xid)
1006{
1007	int		i;
1008
1009	i = reply_xid % (u_int32_t)NFORWARD;
1010	if ((FINFO[i].flag & FINFO_ACTIVE) &&
1011	    (FINFO[i].forward_xid == reply_xid)) {
1012		return (&FINFO[i]);
1013	}
1014	return (NULL);
1015}
1016
1017static int
1018free_slot_by_xid(u_int32_t xid)
1019{
1020	int entry;
1021
1022	entry = xid % (u_int32_t)NFORWARD;
1023	return (free_slot_by_index(entry));
1024}
1025
1026static int
1027free_slot_by_index(int index)
1028{
1029	struct finfo	*fi;
1030
1031	fi = &FINFO[index];
1032	if (fi->flag & FINFO_ACTIVE) {
1033		netbuffree(fi->caller_addr);
1034		/* XXX may be too big, but can't access xprt array here */
1035		if (fi->forward_fd >= svc_maxfd)
1036			svc_maxfd--;
1037		free(fi->uaddr);
1038		fi->flag &= ~FINFO_ACTIVE;
1039		rpcb_rmtcalls--;
1040		return (1);
1041	}
1042	return (0);
1043}
1044
1045static int
1046netbufcmp(struct netbuf *n1, struct netbuf *n2)
1047{
1048	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1049}
1050
1051static struct netbuf *
1052netbufdup(struct netbuf *ap)
1053{
1054	struct netbuf  *np;
1055
1056	if ((np = malloc(sizeof(struct netbuf))) == NULL)
1057		return (NULL);
1058	if ((np->buf = malloc(ap->len)) == NULL) {
1059		free(np);
1060		return (NULL);
1061	}
1062	np->maxlen = np->len = ap->len;
1063	memcpy(np->buf, ap->buf, ap->len);
1064	return (np);
1065}
1066
1067static void
1068netbuffree(struct netbuf *ap)
1069{
1070	free(ap->buf);
1071	free(ap);
1072}
1073
1074
1075#define	MASKVAL	(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
1076extern bool_t __svc_clean_idle(fd_set *, int, bool_t);
1077
1078void
1079my_svc_run(void)
1080{
1081	size_t nfds;
1082	struct pollfd pollfds[FD_SETSIZE];
1083	int poll_ret, check_ret;
1084	int n;
1085#ifdef SVC_RUN_DEBUG
1086	int i;
1087#endif
1088	register struct pollfd	*p;
1089	fd_set cleanfds;
1090
1091	for (;;) {
1092		p = pollfds;
1093		for (n = 0; n <= svc_maxfd; n++) {
1094			if (FD_ISSET(n, &svc_fdset)) {
1095				p->fd = n;
1096				p->events = MASKVAL;
1097				p++;
1098			}
1099		}
1100		nfds = p - pollfds;
1101		poll_ret = 0;
1102#ifdef SVC_RUN_DEBUG
1103		if (debugging) {
1104			fprintf(stderr, "polling for read on fd < ");
1105			for (i = 0, p = pollfds; i < nfds; i++, p++)
1106				if (p->events)
1107					fprintf(stderr, "%d ", p->fd);
1108			fprintf(stderr, ">\n");
1109		}
1110#endif
1111		switch (poll_ret = poll(pollfds, nfds, 30 * 1000)) {
1112		case -1:
1113			/*
1114			 * We ignore all errors, continuing with the assumption
1115			 * that it was set by the signal handlers (or any
1116			 * other outside event) and not caused by poll().
1117			 */
1118		case 0:
1119			cleanfds = svc_fdset;
1120			__svc_clean_idle(&cleanfds, 30, FALSE);
1121			continue;
1122		default:
1123#ifdef SVC_RUN_DEBUG
1124			if (debugging) {
1125				fprintf(stderr, "poll returned read fds < ");
1126				for (i = 0, p = pollfds; i < nfds; i++, p++)
1127					if (p->revents)
1128						fprintf(stderr, "%d ", p->fd);
1129				fprintf(stderr, ">\n");
1130			}
1131#endif
1132			/*
1133			 * If we found as many replies on callback fds
1134			 * as the number of descriptors selectable which
1135			 * poll() returned, there can be no more so we
1136			 * don't call svc_getreq_poll.  Otherwise, there
1137			 * must be another so we must call svc_getreq_poll.
1138			 */
1139			if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
1140			    poll_ret)
1141				continue;
1142			svc_getreq_poll(pollfds, poll_ret-check_ret);
1143		}
1144#ifdef SVC_RUN_DEBUG
1145		if (debugging) {
1146			fprintf(stderr, "svc_maxfd now %u\n", svc_maxfd);
1147		}
1148#endif
1149	}
1150}
1151
1152static int
1153check_rmtcalls(struct pollfd *pfds, int nfds)
1154{
1155	int j, ncallbacks_found = 0, rmtcalls_pending;
1156	SVCXPRT *xprt;
1157
1158	if (rpcb_rmtcalls == 0)
1159		return (0);
1160
1161	rmtcalls_pending = rpcb_rmtcalls;
1162	for (j = 0; j < nfds; j++) {
1163		if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
1164			if (pfds[j].revents) {
1165				ncallbacks_found++;
1166#ifdef DEBUG_RMTCALL
1167			if (debugging)
1168				fprintf(stderr,
1169"my_svc_run:  polled on forwarding fd %d, netid %s - calling handle_reply\n",
1170		pfds[j].fd, xprt->xp_netid);
1171#endif
1172				handle_reply(pfds[j].fd, xprt);
1173				pfds[j].revents = 0;
1174				if (ncallbacks_found >= rmtcalls_pending) {
1175					break;
1176				}
1177			}
1178		}
1179	}
1180	return (ncallbacks_found);
1181}
1182
1183static void
1184xprt_set_caller(SVCXPRT *xprt, struct finfo *fi)
1185{
1186	u_int32_t *xidp;
1187
1188	*(svc_getrpccaller(xprt)) = *(fi->caller_addr);
1189	xidp = __rpcb_get_dg_xidp(xprt);
1190	*xidp = fi->caller_xid;
1191}
1192
1193/*
1194 * Call svcerr_systemerr() only if RPCBVERS4
1195 */
1196static void
1197send_svcsyserr(SVCXPRT *xprt, struct finfo *fi)
1198{
1199	if (fi->reply_type == RPCBPROC_INDIRECT) {
1200		xprt_set_caller(xprt, fi);
1201		svcerr_systemerr(xprt);
1202	}
1203	return;
1204}
1205
1206static void
1207handle_reply(int fd, SVCXPRT *xprt)
1208{
1209	XDR		reply_xdrs;
1210	struct rpc_msg	reply_msg;
1211	struct rpc_err	reply_error;
1212	char		*buffer;
1213	struct finfo	*fi;
1214	int		inlen, pos, len;
1215	struct r_rmtcall_args a;
1216	struct sockaddr_storage ss;
1217	socklen_t fromlen;
1218#ifdef SVC_RUN_DEBUG
1219	char *uaddr;
1220#endif
1221
1222	buffer = malloc(RPC_BUF_MAX);
1223	if (buffer == NULL)
1224		goto done;
1225
1226	do {
1227		fromlen = sizeof(ss);
1228		inlen = recvfrom(fd, buffer, RPC_BUF_MAX, 0,
1229			    (struct sockaddr *)&ss, &fromlen);
1230	} while (inlen < 0 && errno == EINTR);
1231	if (inlen < 0) {
1232		if (debugging)
1233			fprintf(stderr,
1234	"handle_reply:  recvfrom returned %d, errno %d\n", inlen, errno);
1235		goto done;
1236	}
1237
1238	reply_msg.acpted_rply.ar_verf = _null_auth;
1239	reply_msg.acpted_rply.ar_results.where = 0;
1240	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
1241
1242	xdrmem_create(&reply_xdrs, buffer, (u_int)inlen, XDR_DECODE);
1243	if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
1244		if (debugging)
1245			(void) fprintf(stderr,
1246				"handle_reply:  xdr_replymsg failed\n");
1247		goto done;
1248	}
1249	fi = forward_find(reply_msg.rm_xid);
1250#ifdef	SVC_RUN_DEBUG
1251	if (debugging) {
1252		fprintf(stderr, "handle_reply:  reply xid: %d fi addr: %p\n",
1253			reply_msg.rm_xid, fi);
1254	}
1255#endif
1256	if (fi == NULL) {
1257		goto done;
1258	}
1259	_seterr_reply(&reply_msg, &reply_error);
1260	if (reply_error.re_status != RPC_SUCCESS) {
1261		if (debugging)
1262			(void) fprintf(stderr, "handle_reply:  %s\n",
1263				clnt_sperrno(reply_error.re_status));
1264		send_svcsyserr(xprt, fi);
1265		goto done;
1266	}
1267	pos = XDR_GETPOS(&reply_xdrs);
1268	len = inlen - pos;
1269	a.rmt_args.args = &buffer[pos];
1270	a.rmt_args.arglen = len;
1271	a.rmt_uaddr = fi->uaddr;
1272	a.rmt_localvers = fi->versnum;
1273
1274	xprt_set_caller(xprt, fi);
1275#ifdef	SVC_RUN_DEBUG
1276	uaddr =	taddr2uaddr(rpcbind_get_conf("udp"),
1277				    svc_getrpccaller(xprt));
1278	if (debugging) {
1279		fprintf(stderr, "handle_reply:  forwarding address %s to %s\n",
1280			a.rmt_uaddr, uaddr ? uaddr : "unknown");
1281	}
1282	if (uaddr)
1283		free(uaddr);
1284#endif
1285	svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (char *) &a);
1286done:
1287	if (buffer)
1288		free(buffer);
1289
1290	if (reply_msg.rm_xid == 0) {
1291#ifdef	SVC_RUN_DEBUG
1292	if (debugging) {
1293		fprintf(stderr, "handle_reply:  NULL xid on exit!\n");
1294	}
1295#endif
1296	} else
1297		(void) free_slot_by_xid(reply_msg.rm_xid);
1298	return;
1299}
1300
1301static void
1302find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
1303{
1304	register rpcblist_ptr rbl;
1305	unsigned int lowv = 0;
1306	unsigned int highv = 0;
1307
1308	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1309		if ((rbl->rpcb_map.r_prog != prog) ||
1310		    ((rbl->rpcb_map.r_netid != NULL) &&
1311			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1312			continue;
1313		if (lowv == 0) {
1314			highv = rbl->rpcb_map.r_vers;
1315			lowv = highv;
1316		} else if (rbl->rpcb_map.r_vers < lowv) {
1317			lowv = rbl->rpcb_map.r_vers;
1318		} else if (rbl->rpcb_map.r_vers > highv) {
1319			highv = rbl->rpcb_map.r_vers;
1320		}
1321	}
1322	*lowvp = lowv;
1323	*highvp = highv;
1324	return;
1325}
1326
1327/*
1328 * returns the item with the given program, version number and netid.
1329 * If that version number is not found, it returns the item with that
1330 * program number, so that address is now returned to the caller. The
1331 * caller when makes a call to this program, version number, the call
1332 * will fail and it will return with PROGVERS_MISMATCH. The user can
1333 * then determine the highest and the lowest version number for this
1334 * program using clnt_geterr() and use those program version numbers.
1335 *
1336 * Returns the RPCBLIST for the given prog, vers and netid
1337 */
1338static rpcblist_ptr
1339find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
1340{
1341	register rpcblist_ptr hit = NULL;
1342	register rpcblist_ptr rbl;
1343
1344	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1345		if ((rbl->rpcb_map.r_prog != prog) ||
1346		    ((rbl->rpcb_map.r_netid != NULL) &&
1347			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1348			continue;
1349		hit = rbl;
1350		if (rbl->rpcb_map.r_vers == vers)
1351			break;
1352	}
1353	return (hit);
1354}
1355
1356/*
1357 * Copies the name associated with the uid of the caller and returns
1358 * a pointer to it.  Similar to getwd().
1359 */
1360static char *
1361getowner(SVCXPRT *transp, char *owner, size_t ownersize)
1362{
1363	uid_t uid;
1364
1365	if (__rpc_get_local_uid(transp, &uid) < 0)
1366                strlcpy(owner, "unknown", ownersize);
1367	else if (uid == 0)
1368		strlcpy(owner, "superuser", ownersize);
1369	else
1370		snprintf(owner, ownersize, "%d", uid);
1371
1372	return owner;
1373}
1374
1375#ifdef PORTMAP
1376/*
1377 * Add this to the pmap list only if it is UDP or TCP.
1378 */
1379static int
1380add_pmaplist(RPCB *arg)
1381{
1382	struct pmap pmap;
1383	struct pmaplist *pml;
1384	int h1, h2, h3, h4, p1, p2;
1385
1386	if (strcmp(arg->r_netid, udptrans) == 0) {
1387		/* It is UDP! */
1388		pmap.pm_prot = IPPROTO_UDP;
1389	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1390		/* It is TCP */
1391		pmap.pm_prot = IPPROTO_TCP;
1392	} else
1393		/* Not an IP protocol */
1394		return (0);
1395
1396	/* interpret the universal address for TCP/IP */
1397	if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
1398		&h1, &h2, &h3, &h4, &p1, &p2) != 6)
1399		return (0);
1400	pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1401	pmap.pm_prog = arg->r_prog;
1402	pmap.pm_vers = arg->r_vers;
1403	/*
1404	 * add to END of list
1405	 */
1406	pml = malloc(sizeof (struct pmaplist));
1407	if (pml == NULL) {
1408		(void) syslog(LOG_ERR, "rpcbind: no memory!\n");
1409		return (1);
1410	}
1411	pml->pml_map = pmap;
1412	pml->pml_next = NULL;
1413	if (list_pml == NULL) {
1414		list_pml = pml;
1415	} else {
1416		struct pmaplist *fnd;
1417
1418		/* Attach to the end of the list */
1419		for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
1420			;
1421		fnd->pml_next = pml;
1422	}
1423	return (0);
1424}
1425
1426/*
1427 * Delete this from the pmap list only if it is UDP or TCP.
1428 */
1429static int
1430del_pmaplist(RPCB *arg)
1431{
1432	struct pmaplist *pml;
1433	struct pmaplist *prevpml, *fnd;
1434	unsigned long prot;
1435
1436	if (strcmp(arg->r_netid, udptrans) == 0) {
1437		/* It is UDP! */
1438		prot = IPPROTO_UDP;
1439	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1440		/* It is TCP */
1441		prot = IPPROTO_TCP;
1442	} else if (arg->r_netid[0] == 0) {
1443		prot = 0;	/* Remove all occurrences */
1444	} else {
1445		/* Not an IP protocol */
1446		return (0);
1447	}
1448	for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
1449		if ((pml->pml_map.pm_prog != arg->r_prog) ||
1450			(pml->pml_map.pm_vers != arg->r_vers) ||
1451			(prot && (pml->pml_map.pm_prot != prot))) {
1452			/* both pml & prevpml move forwards */
1453			prevpml = pml;
1454			pml = pml->pml_next;
1455			continue;
1456		}
1457		/* found it; pml moves forward, prevpml stays */
1458		fnd = pml;
1459		pml = pml->pml_next;
1460		if (prevpml == NULL)
1461			list_pml = pml;
1462		else
1463			prevpml->pml_next = pml;
1464		free(fnd);
1465	}
1466	return (0);
1467}
1468#endif /* PORTMAP */
1469