1/*	$NetBSD: rpcb_svc_com.c,v 1.9 2002/11/08 00:16:39 fvdl Exp $	*/
2/*	$FreeBSD$ */
3
4/*-
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Copyright (c) 2009, Sun Microsystems, Inc.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 * - Redistributions of source code must retain the above copyright notice,
13 *   this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above copyright notice,
15 *   this list of conditions and the following disclaimer in the documentation
16 *   and/or other materials provided with the distribution.
17 * - Neither the name of Sun Microsystems, Inc. nor the names of its
18 *   contributors may be used to endorse or promote products derived
19 *   from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33/*
34 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
35 */
36
37/* #ident	"@(#)rpcb_svc_com.c	1.18	94/05/02 SMI" */
38
39/*
40 * rpcb_svc_com.c
41 * The commom server procedure for the rpcbind.
42 */
43
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <sys/param.h>
47#include <sys/poll.h>
48#include <sys/socket.h>
49#include <rpc/rpc.h>
50#include <rpc/rpcb_prot.h>
51#include <rpc/svc_dg.h>
52#include <assert.h>
53#include <netconfig.h>
54#include <errno.h>
55#include <syslog.h>
56#include <stdio.h>
57#include <string.h>
58#include <stdlib.h>
59#include <unistd.h>
60#ifdef PORTMAP
61#include <netinet/in.h>
62#include <rpc/rpc_com.h>
63#include <rpc/pmap_prot.h>
64#endif /* PORTMAP */
65
66#include "rpcbind.h"
67
68#define RPC_BUF_MAX	65536	/* can be raised if required */
69
70static char *nullstring = "";
71static int rpcb_rmtcalls;
72
73struct rmtcallfd_list {
74	int fd;
75	SVCXPRT *xprt;
76	char *netid;
77	struct rmtcallfd_list *next;
78};
79
80#define NFORWARD        64
81#define MAXTIME_OFF     300     /* 5 minutes */
82
83struct finfo {
84	int             flag;
85#define FINFO_ACTIVE    0x1
86	u_int32_t       caller_xid;
87        struct netbuf   *caller_addr;
88	u_int32_t       forward_xid;
89	int             forward_fd;
90	char            *uaddr;
91	rpcproc_t       reply_type;
92	rpcvers_t       versnum;
93	time_t          time;
94};
95static struct finfo     FINFO[NFORWARD];
96
97
98static bool_t xdr_encap_parms(XDR *, struct encap_parms *);
99static bool_t xdr_rmtcall_args(XDR *, struct r_rmtcall_args *);
100static bool_t xdr_rmtcall_result(XDR *, struct r_rmtcall_args *);
101static bool_t xdr_opaque_parms(XDR *, struct r_rmtcall_args *);
102static int find_rmtcallfd_by_netid(char *);
103static SVCXPRT *find_rmtcallxprt_by_fd(int);
104static int forward_register(u_int32_t, struct netbuf *, int, char *,
105    rpcproc_t, rpcvers_t, u_int32_t *);
106static struct finfo *forward_find(u_int32_t);
107static int free_slot_by_xid(u_int32_t);
108static int free_slot_by_index(int);
109static int netbufcmp(struct netbuf *, struct netbuf *);
110static struct netbuf *netbufdup(struct netbuf *);
111static void netbuffree(struct netbuf *);
112static int check_rmtcalls(struct pollfd *, int);
113static void xprt_set_caller(SVCXPRT *, struct finfo *);
114static void send_svcsyserr(SVCXPRT *, struct finfo *);
115static void handle_reply(int, SVCXPRT *);
116static void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
117static rpcblist_ptr find_service(rpcprog_t, rpcvers_t, char *);
118static char *getowner(SVCXPRT *, char *, size_t);
119static int add_pmaplist(RPCB *);
120static int del_pmaplist(RPCB *);
121
122/*
123 * Set a mapping of program, version, netid
124 */
125/* ARGSUSED */
126void *
127rpcbproc_set_com(void *arg, struct svc_req *rqstp __unused, SVCXPRT *transp,
128		 rpcvers_t rpcbversnum)
129{
130	RPCB *regp = (RPCB *)arg;
131	static bool_t ans;
132	char owner[64];
133
134#ifdef RPCBIND_DEBUG
135	if (debugging)
136		fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
137		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
138		    regp->r_netid, regp->r_addr);
139#endif
140	ans = map_set(regp, getowner(transp, owner, sizeof owner));
141#ifdef RPCBIND_DEBUG
142	if (debugging)
143		fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
144#endif
145	/* XXX: should have used some defined constant here */
146	rpcbs_set(rpcbversnum - 2, ans);
147	return (void *)&ans;
148}
149
150bool_t
151map_set(RPCB *regp, char *owner)
152{
153	RPCB reg, *a;
154	rpcblist_ptr rbl, fnd;
155
156	reg = *regp;
157	/*
158	 * check to see if already used
159	 * find_service returns a hit even if
160	 * the versions don't match, so check for it
161	 */
162	fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
163	if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
164		if (!strcmp(fnd->rpcb_map.r_addr, reg.r_addr))
165			/*
166			 * if these match then it is already
167			 * registered so just say "OK".
168			 */
169			return (TRUE);
170		else
171			return (FALSE);
172	}
173	/*
174	 * add to the end of the list
175	 */
176	rbl = malloc(sizeof (RPCBLIST));
177	if (rbl == NULL)
178		return (FALSE);
179	a = &(rbl->rpcb_map);
180	a->r_prog = reg.r_prog;
181	a->r_vers = reg.r_vers;
182	a->r_netid = strdup(reg.r_netid);
183	a->r_addr = strdup(reg.r_addr);
184	a->r_owner = strdup(owner);
185	if (!a->r_addr || !a->r_netid || !a->r_owner) {
186		free(a->r_netid);
187		free(a->r_addr);
188		free(a->r_owner);
189		free(rbl);
190		return (FALSE);
191	}
192	rbl->rpcb_next = (rpcblist_ptr)NULL;
193	if (list_rbl == NULL) {
194		list_rbl = rbl;
195	} else {
196		for (fnd = list_rbl; fnd->rpcb_next;
197			fnd = fnd->rpcb_next)
198			;
199		fnd->rpcb_next = rbl;
200	}
201#ifdef PORTMAP
202	(void) add_pmaplist(regp);
203#endif
204	return (TRUE);
205}
206
207/*
208 * Unset a mapping of program, version, netid
209 */
210/* ARGSUSED */
211void *
212rpcbproc_unset_com(void *arg, struct svc_req *rqstp __unused, SVCXPRT *transp,
213		   rpcvers_t rpcbversnum)
214{
215	RPCB *regp = (RPCB *)arg;
216	static bool_t ans;
217	char owner[64];
218
219#ifdef RPCBIND_DEBUG
220	if (debugging)
221		fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
222		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
223		    regp->r_netid);
224#endif
225	ans = map_unset(regp, getowner(transp, owner, sizeof owner));
226#ifdef RPCBIND_DEBUG
227	if (debugging)
228		fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
229#endif
230	/* XXX: should have used some defined constant here */
231	rpcbs_unset(rpcbversnum - 2, ans);
232	return (void *)&ans;
233}
234
235bool_t
236map_unset(RPCB *regp, char *owner)
237{
238	int ans = 0;
239	rpcblist_ptr rbl, prev, tmp;
240
241	if (owner == NULL)
242		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	netbuffree(taddr);
373	taddr = NULL;
374	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
375	    ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
376		(void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
377		return (void *)&nbuf;
378	}
379	return (void *)taddr;
380}
381
382/*
383 * Convert taddr to uaddr. Should be used only by
384 * local servers/clients. (kernel level stuff only)
385 */
386/* ARGSUSED */
387void *
388rpcbproc_taddr2uaddr_com(void *arg, struct svc_req *rqstp __unused,
389			 SVCXPRT *transp, rpcvers_t rpcbversnum __unused)
390{
391	struct netbuf *taddr = (struct netbuf *)arg;
392	static char *uaddr;
393	struct netconfig *nconf;
394
395#ifdef CHEW_FDS
396	int fd;
397
398	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
399		uaddr = (char *)strerror(errno);
400		return (&uaddr);
401	}
402#endif /* CHEW_FDS */
403	if (uaddr != NULL && uaddr != nullstring) {
404		free(uaddr);
405		uaddr = NULL;
406	}
407	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
408		((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
409		uaddr = nullstring;
410	}
411	return (void *)&uaddr;
412}
413
414
415static bool_t
416xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
417{
418	return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen),
419	    RPC_MAXDATASIZE));
420}
421
422/*
423 * XDR remote call arguments.  It ignores the address part.
424 * written for XDR_DECODE direction only
425 */
426static bool_t
427xdr_rmtcall_args(XDR *xdrs, struct r_rmtcall_args *cap)
428{
429	/* does not get the address or the arguments */
430	if (xdr_rpcprog(xdrs, &(cap->rmt_prog)) &&
431	    xdr_rpcvers(xdrs, &(cap->rmt_vers)) &&
432	    xdr_rpcproc(xdrs, &(cap->rmt_proc))) {
433		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
434	}
435	return (FALSE);
436}
437
438/*
439 * XDR remote call results along with the address.  Ignore
440 * program number, version  number and proc number.
441 * Written for XDR_ENCODE direction only.
442 */
443static bool_t
444xdr_rmtcall_result(XDR *xdrs, struct r_rmtcall_args *cap)
445{
446	bool_t result;
447
448#ifdef PORTMAP
449	if (cap->rmt_localvers == PMAPVERS) {
450		int h1, h2, h3, h4, p1, p2;
451		u_long port;
452
453		/* interpret the universal address for TCP/IP */
454		if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
455			&h1, &h2, &h3, &h4, &p1, &p2) != 6)
456			return (FALSE);
457		port = ((p1 & 0xff) << 8) + (p2 & 0xff);
458		result = xdr_u_long(xdrs, &port);
459	} else
460#endif
461		if ((cap->rmt_localvers == RPCBVERS) ||
462		    (cap->rmt_localvers == RPCBVERS4)) {
463		result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
464	} else {
465		return (FALSE);
466	}
467	if (result == TRUE)
468		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
469	return (FALSE);
470}
471
472/*
473 * only worries about the struct encap_parms part of struct r_rmtcall_args.
474 * The arglen must already be set!!
475 */
476static bool_t
477xdr_opaque_parms(XDR *xdrs, struct r_rmtcall_args *cap)
478{
479	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
480}
481
482static struct rmtcallfd_list *rmthead;
483static struct rmtcallfd_list *rmttail;
484
485int
486create_rmtcall_fd(struct netconfig *nconf)
487{
488	int fd;
489	struct rmtcallfd_list *rmt;
490	SVCXPRT *xprt;
491
492	if ((fd = __rpc_nconf2fd(nconf)) == -1) {
493		if (debugging)
494			fprintf(stderr,
495	"create_rmtcall_fd: couldn't open \"%s\" (errno %d)\n",
496			nconf->nc_device, errno);
497		return (-1);
498	}
499	xprt = svc_tli_create(fd, 0, (struct t_bind *) 0, 0, 0);
500	if (xprt == NULL) {
501		if (debugging)
502			fprintf(stderr,
503				"create_rmtcall_fd: svc_tli_create failed\n");
504		return (-1);
505	}
506	rmt = malloc(sizeof (struct rmtcallfd_list));
507	if (rmt == NULL) {
508		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
509		return (-1);
510	}
511	rmt->xprt = xprt;
512	rmt->netid = strdup(nconf->nc_netid);
513	xprt->xp_netid = rmt->netid;
514	rmt->fd = fd;
515	rmt->next = NULL;
516	if (rmthead == NULL) {
517		rmthead = rmt;
518		rmttail = rmt;
519	} else {
520		rmttail->next = rmt;
521		rmttail = rmt;
522	}
523	/* XXX not threadsafe */
524	if (fd > svc_maxfd)
525		svc_maxfd = fd;
526	FD_SET(fd, &svc_fdset);
527	return (fd);
528}
529
530static int
531find_rmtcallfd_by_netid(char *netid)
532{
533	struct rmtcallfd_list *rmt;
534
535	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
536		if (strcmp(netid, rmt->netid) == 0) {
537			return (rmt->fd);
538		}
539	}
540	return (-1);
541}
542
543static SVCXPRT *
544find_rmtcallxprt_by_fd(int fd)
545{
546	struct rmtcallfd_list *rmt;
547
548	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
549		if (fd == rmt->fd) {
550			return (rmt->xprt);
551		}
552	}
553	return (NULL);
554}
555
556
557/*
558 * Call a remote procedure service.  This procedure is very quiet when things
559 * go wrong.  The proc is written to support broadcast rpc.  In the broadcast
560 * case, a machine should shut-up instead of complain, lest the requestor be
561 * overrun with complaints at the expense of not hearing a valid reply.
562 * When receiving a request and verifying that the service exists, we
563 *
564 *	receive the request
565 *
566 *	open a new TLI endpoint on the same transport on which we received
567 *	the original request
568 *
569 *	remember the original request's XID (which requires knowing the format
570 *	of the svc_dg_data structure)
571 *
572 *	forward the request, with a new XID, to the requested service,
573 *	remembering the XID used to send this request (for later use in
574 *	reassociating the answer with the original request), the requestor's
575 *	address, the file descriptor on which the forwarded request is
576 *	made and the service's address.
577 *
578 *	mark the file descriptor on which we anticipate receiving a reply from
579 *	the service and one to select for in our private svc_run procedure
580 *
581 * At some time in the future, a reply will be received from the service to
582 * which we forwarded the request.  At that time, we detect that the socket
583 * used was for forwarding (by looking through the finfo structures to see
584 * whether the fd corresponds to one of those) and call handle_reply() to
585 *
586 *	receive the reply
587 *
588 *	bundle the reply, along with the service's universal address
589 *
590 *	create a SVCXPRT structure and use a version of svc_sendreply
591 *	that allows us to specify the reply XID and destination, send the reply
592 *	to the original requestor.
593 */
594
595void
596rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp,
597		    rpcproc_t reply_type, rpcvers_t versnum)
598{
599	register rpcblist_ptr rbl;
600	struct netconfig *nconf;
601	struct netbuf *caller;
602	struct r_rmtcall_args a;
603	char *buf_alloc = NULL, *outbufp;
604	char *outbuf_alloc = NULL;
605	char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
606	struct netbuf *na = (struct netbuf *) NULL;
607	struct rpc_msg call_msg;
608	int outlen;
609	u_int sendsz;
610	XDR outxdr;
611	AUTH *auth;
612	int fd = -1;
613	char *uaddr, *m_uaddr = NULL, *local_uaddr = NULL;
614	u_int32_t *xidp;
615	struct __rpc_sockinfo si;
616	struct sockaddr *localsa;
617	struct netbuf tbuf;
618
619	if (!__rpc_fd2sockinfo(transp->xp_fd, &si)) {
620		if (reply_type == RPCBPROC_INDIRECT)
621			svcerr_systemerr(transp);
622		return;
623	}
624	if (si.si_socktype != SOCK_DGRAM)
625		return;	/* Only datagram type accepted */
626	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, UDPMSGSIZE);
627	if (sendsz == 0) {	/* data transfer not supported */
628		if (reply_type == RPCBPROC_INDIRECT)
629			svcerr_systemerr(transp);
630		return;
631	}
632	/*
633	 * Should be multiple of 4 for XDR.
634	 */
635	sendsz = roundup(sendsz, 4);
636	if (sendsz > RPC_BUF_MAX) {
637#ifdef	notyet
638		buf_alloc = alloca(sendsz);		/* not in IDR2? */
639#else
640		buf_alloc = malloc(sendsz);
641#endif	/* notyet */
642		if (buf_alloc == NULL) {
643			if (debugging)
644				fprintf(stderr,
645					"rpcbproc_callit_com:  No Memory!\n");
646			if (reply_type == RPCBPROC_INDIRECT)
647				svcerr_systemerr(transp);
648			return;
649		}
650		a.rmt_args.args = buf_alloc;
651	} else {
652		a.rmt_args.args = buf;
653	}
654
655	call_msg.rm_xid = 0;	/* For error checking purposes */
656	if (!svc_getargs(transp, (xdrproc_t) xdr_rmtcall_args, (char *) &a)) {
657		if (reply_type == RPCBPROC_INDIRECT)
658			svcerr_decode(transp);
659		if (debugging)
660			fprintf(stderr,
661			"rpcbproc_callit_com:  svc_getargs failed\n");
662		goto error;
663	}
664
665	if (!check_callit(transp, &a, versnum)) {
666		svcerr_weakauth(transp);
667		goto error;
668	}
669
670	caller = svc_getrpccaller(transp);
671#ifdef RPCBIND_DEBUG
672	if (debugging) {
673		uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
674		fprintf(stderr, "%s %s req for (%lu, %lu, %lu, %s) from %s : ",
675			versnum == PMAPVERS ? "pmap_rmtcall" :
676			versnum == RPCBVERS ? "rpcb_rmtcall" :
677			versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
678			reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
679			(unsigned long)a.rmt_prog, (unsigned long)a.rmt_vers,
680			(unsigned long)a.rmt_proc, transp->xp_netid,
681			uaddr ? uaddr : "unknown");
682		free(uaddr);
683	}
684#endif
685
686	rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
687
688	rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
689			a.rmt_proc, transp->xp_netid, rbl);
690
691	if (rbl == (rpcblist_ptr)NULL) {
692#ifdef RPCBIND_DEBUG
693		if (debugging)
694			fprintf(stderr, "not found\n");
695#endif
696		if (reply_type == RPCBPROC_INDIRECT)
697			svcerr_noprog(transp);
698		goto error;
699	}
700	if (rbl->rpcb_map.r_vers != a.rmt_vers) {
701		if (reply_type == RPCBPROC_INDIRECT) {
702			rpcvers_t vers_low, vers_high;
703
704			find_versions(a.rmt_prog, transp->xp_netid,
705				&vers_low, &vers_high);
706			svcerr_progvers(transp, vers_low, vers_high);
707		}
708		goto error;
709	}
710
711#ifdef RPCBIND_DEBUG
712	if (debugging)
713		fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
714#endif
715	/*
716	 *	Check whether this entry is valid and a server is present
717	 *	Mergeaddr() returns NULL if no such entry is present, and
718	 *	returns "" if the entry was present but the server is not
719	 *	present (i.e., it crashed).
720	 */
721	if (reply_type == RPCBPROC_INDIRECT) {
722		uaddr = mergeaddr(transp, transp->xp_netid,
723			rbl->rpcb_map.r_addr, NULL);
724		if (uaddr == NULL || uaddr[0] == '\0') {
725			svcerr_noprog(transp);
726			free(uaddr);
727			goto error;
728		}
729		free(uaddr);
730	}
731	nconf = rpcbind_get_conf(transp->xp_netid);
732	if (nconf == (struct netconfig *)NULL) {
733		if (reply_type == RPCBPROC_INDIRECT)
734			svcerr_systemerr(transp);
735		if (debugging)
736			fprintf(stderr,
737			"rpcbproc_callit_com:  rpcbind_get_conf failed\n");
738		goto error;
739	}
740	localsa = local_sa(((struct sockaddr *)caller->buf)->sa_family);
741	if (localsa == NULL) {
742		if (debugging)
743			fprintf(stderr,
744			"rpcbproc_callit_com: no local address\n");
745		goto error;
746	}
747	tbuf.len = tbuf.maxlen = localsa->sa_len;
748	tbuf.buf = localsa;
749	local_uaddr =
750	    addrmerge(&tbuf, rbl->rpcb_map.r_addr, NULL, nconf->nc_netid);
751	m_uaddr = addrmerge(caller, rbl->rpcb_map.r_addr, NULL,
752			nconf->nc_netid);
753#ifdef RPCBIND_DEBUG
754	if (debugging)
755		fprintf(stderr, "merged uaddr %s\n", m_uaddr);
756#endif
757	if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
758		if (reply_type == RPCBPROC_INDIRECT)
759			svcerr_systemerr(transp);
760		goto error;
761	}
762	xidp = __rpcb_get_dg_xidp(transp);
763	switch (forward_register(*xidp, caller, fd, m_uaddr, reply_type,
764	    versnum, &call_msg.rm_xid)) {
765	case 1:
766		/* Success; forward_register() will free m_uaddr for us. */
767		m_uaddr = NULL;
768		break;
769	case 0:
770		/*
771		 * A duplicate request for the slow server.  Let's not
772		 * beat on it any more.
773		 */
774		if (debugging)
775			fprintf(stderr,
776			"rpcbproc_callit_com:  duplicate request\n");
777		goto error;
778	case -1:
779		/*  forward_register failed.  Perhaps no memory. */
780		if (debugging)
781			fprintf(stderr,
782			"rpcbproc_callit_com:  forward_register failed\n");
783		goto error;
784	}
785
786#ifdef DEBUG_RMTCALL
787	if (debugging)
788		fprintf(stderr,
789			"rpcbproc_callit_com:  original XID %x, new XID %x\n",
790				*xidp, call_msg.rm_xid);
791#endif
792	call_msg.rm_direction = CALL;
793	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
794	call_msg.rm_call.cb_prog = a.rmt_prog;
795	call_msg.rm_call.cb_vers = a.rmt_vers;
796	if (sendsz > RPC_BUF_MAX) {
797#ifdef	notyet
798		outbuf_alloc = alloca(sendsz);	/* not in IDR2? */
799#else
800		outbuf_alloc = malloc(sendsz);
801#endif	/* notyet */
802		if (outbuf_alloc == NULL) {
803			if (reply_type == RPCBPROC_INDIRECT)
804				svcerr_systemerr(transp);
805			if (debugging)
806				fprintf(stderr,
807				"rpcbproc_callit_com:  No memory!\n");
808			goto error;
809		}
810		xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
811	} else {
812		xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
813	}
814	if (!xdr_callhdr(&outxdr, &call_msg)) {
815		if (reply_type == RPCBPROC_INDIRECT)
816			svcerr_systemerr(transp);
817		if (debugging)
818			fprintf(stderr,
819			"rpcbproc_callit_com:  xdr_callhdr failed\n");
820		goto error;
821	}
822	if (!xdr_u_int32_t(&outxdr, &(a.rmt_proc))) {
823		if (reply_type == RPCBPROC_INDIRECT)
824			svcerr_systemerr(transp);
825		if (debugging)
826			fprintf(stderr,
827			"rpcbproc_callit_com:  xdr_u_long failed\n");
828		goto error;
829	}
830
831	if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
832		auth = authnone_create();
833	} else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
834		struct authunix_parms *au;
835
836		au = (struct authunix_parms *)rqstp->rq_clntcred;
837		auth = authunix_create(au->aup_machname,
838				au->aup_uid, au->aup_gid,
839				au->aup_len, au->aup_gids);
840		if (auth == NULL) /* fall back */
841			auth = authnone_create();
842	} else {
843		/* we do not support any other authentication scheme */
844		if (debugging)
845			fprintf(stderr,
846"rpcbproc_callit_com:  oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
847		if (reply_type == RPCBPROC_INDIRECT)
848			svcerr_weakauth(transp); /* XXX too strong.. */
849		goto error;
850	}
851	if (auth == NULL) {
852		if (reply_type == RPCBPROC_INDIRECT)
853			svcerr_systemerr(transp);
854		if (debugging)
855			fprintf(stderr,
856		"rpcbproc_callit_com:  authwhatever_create returned NULL\n");
857		goto error;
858	}
859	if (!AUTH_MARSHALL(auth, &outxdr)) {
860		if (reply_type == RPCBPROC_INDIRECT)
861			svcerr_systemerr(transp);
862		AUTH_DESTROY(auth);
863		if (debugging)
864			fprintf(stderr,
865		"rpcbproc_callit_com:  AUTH_MARSHALL failed\n");
866		goto error;
867	}
868	AUTH_DESTROY(auth);
869	if (!xdr_opaque_parms(&outxdr, &a)) {
870		if (reply_type == RPCBPROC_INDIRECT)
871			svcerr_systemerr(transp);
872		if (debugging)
873			fprintf(stderr,
874		"rpcbproc_callit_com:  xdr_opaque_parms failed\n");
875		goto error;
876	}
877	outlen = (int) XDR_GETPOS(&outxdr);
878	if (outbuf_alloc)
879		outbufp = outbuf_alloc;
880	else
881		outbufp = outbuf;
882
883	na = uaddr2taddr(nconf, local_uaddr);
884	if (!na) {
885		if (reply_type == RPCBPROC_INDIRECT)
886			svcerr_systemerr(transp);
887		goto error;
888	}
889
890	if (sendto(fd, outbufp, outlen, 0, (struct sockaddr *)na->buf, na->len)
891	    != outlen) {
892		if (debugging)
893			fprintf(stderr,
894	"rpcbproc_callit_com:  sendto failed:  errno %d\n", errno);
895		if (reply_type == RPCBPROC_INDIRECT)
896			svcerr_systemerr(transp);
897		goto error;
898	}
899	goto out;
900
901error:
902	if (call_msg.rm_xid != 0)
903		(void) free_slot_by_xid(call_msg.rm_xid);
904out:
905	free(local_uaddr);
906	free(buf_alloc);
907	free(outbuf_alloc);
908	netbuffree(na);
909	free(m_uaddr);
910}
911
912/*
913 * Makes an entry into the FIFO for the given request.
914 * Returns 1 on success, 0 if this is a duplicate request, or -1 on error.
915 * *callxidp is set to the xid of the call.
916 */
917static int
918forward_register(u_int32_t caller_xid, struct netbuf *caller_addr,
919		 int forward_fd, char *uaddr, rpcproc_t reply_type,
920		 rpcvers_t versnum, u_int32_t *callxidp)
921{
922	int		i;
923	int		j = 0;
924	time_t		min_time, time_now;
925	static u_int32_t	lastxid;
926	int		entry = -1;
927
928	min_time = FINFO[0].time;
929	time_now = time((time_t *)0);
930	/* initialization */
931	if (lastxid == 0)
932		lastxid = time_now * NFORWARD;
933
934	/*
935	 * Check if it is a duplicate entry. Then,
936	 * try to find an empty slot.  If not available, then
937	 * use the slot with the earliest time.
938	 */
939	for (i = 0; i < NFORWARD; i++) {
940		if (FINFO[i].flag & FINFO_ACTIVE) {
941			if ((FINFO[i].caller_xid == caller_xid) &&
942			    (FINFO[i].reply_type == reply_type) &&
943			    (FINFO[i].versnum == versnum) &&
944			    (!netbufcmp(FINFO[i].caller_addr,
945					    caller_addr))) {
946				FINFO[i].time = time((time_t *)0);
947				return (0);	/* Duplicate entry */
948			} else {
949				/* Should we wait any longer */
950				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
951					(void) free_slot_by_index(i);
952			}
953		}
954		if (entry == -1) {
955			if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
956				entry = i;
957			} else if (FINFO[i].time < min_time) {
958				j = i;
959				min_time = FINFO[i].time;
960			}
961		}
962	}
963	if (entry != -1) {
964		/* use this empty slot */
965		j = entry;
966	} else {
967		(void) free_slot_by_index(j);
968	}
969	if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
970		return (-1);
971	}
972	rpcb_rmtcalls++;	/* no of pending calls */
973	FINFO[j].flag = FINFO_ACTIVE;
974	FINFO[j].reply_type = reply_type;
975	FINFO[j].versnum = versnum;
976	FINFO[j].time = time_now;
977	FINFO[j].caller_xid = caller_xid;
978	FINFO[j].forward_fd = forward_fd;
979	/*
980	 * Though uaddr is not allocated here, it will still be freed
981	 * from free_slot_*().
982	 */
983	FINFO[j].uaddr = uaddr;
984	lastxid = lastxid + NFORWARD;
985	/* Don't allow a zero xid below. */
986	if ((u_int32_t)(lastxid + NFORWARD) <= NFORWARD)
987		lastxid = NFORWARD;
988	FINFO[j].forward_xid = lastxid + j;	/* encode slot */
989	*callxidp = FINFO[j].forward_xid;	/* forward on this xid */
990	return (1);
991}
992
993static struct finfo *
994forward_find(u_int32_t reply_xid)
995{
996	int		i;
997
998	i = reply_xid % (u_int32_t)NFORWARD;
999	if ((FINFO[i].flag & FINFO_ACTIVE) &&
1000	    (FINFO[i].forward_xid == reply_xid)) {
1001		return (&FINFO[i]);
1002	}
1003	return (NULL);
1004}
1005
1006static int
1007free_slot_by_xid(u_int32_t xid)
1008{
1009	int entry;
1010
1011	entry = xid % (u_int32_t)NFORWARD;
1012	return (free_slot_by_index(entry));
1013}
1014
1015static int
1016free_slot_by_index(int index)
1017{
1018	struct finfo	*fi;
1019
1020	fi = &FINFO[index];
1021	if (fi->flag & FINFO_ACTIVE) {
1022		netbuffree(fi->caller_addr);
1023		/* XXX may be too big, but can't access xprt array here */
1024		if (fi->forward_fd >= svc_maxfd)
1025			svc_maxfd--;
1026		free(fi->uaddr);
1027		fi->flag &= ~FINFO_ACTIVE;
1028		rpcb_rmtcalls--;
1029		return (1);
1030	}
1031	return (0);
1032}
1033
1034static int
1035netbufcmp(struct netbuf *n1, struct netbuf *n2)
1036{
1037	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1038}
1039
1040static bool_t
1041netbuf_copybuf(struct netbuf *dst, const struct netbuf *src)
1042{
1043	assert(src->len <= src->maxlen);
1044
1045	if (dst->maxlen < src->len || dst->buf == NULL) {
1046		free(dst->buf);
1047		if ((dst->buf = calloc(1, src->maxlen)) == NULL)
1048			return (FALSE);
1049		dst->maxlen = src->maxlen;
1050	}
1051
1052	dst->len = src->len;
1053	memcpy(dst->buf, src->buf, src->len);
1054
1055	return (TRUE);
1056}
1057
1058static struct netbuf *
1059netbufdup(struct netbuf *ap)
1060{
1061	struct netbuf  *np;
1062
1063	if ((np = calloc(1, sizeof(struct netbuf))) == NULL)
1064		return (NULL);
1065	if (netbuf_copybuf(np, ap) == FALSE) {
1066		free(np);
1067		return (NULL);
1068	}
1069	return (np);
1070}
1071
1072static void
1073netbuffree(struct netbuf *ap)
1074{
1075
1076	if (ap == NULL)
1077		return;
1078	free(ap->buf);
1079	ap->buf = NULL;
1080	free(ap);
1081}
1082
1083
1084#define	MASKVAL	(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
1085extern bool_t __svc_clean_idle(fd_set *, int, bool_t);
1086
1087void
1088my_svc_run(void)
1089{
1090	size_t nfds;
1091	struct pollfd pollfds[FD_SETSIZE + 1];
1092	int poll_ret, check_ret;
1093	int n;
1094#ifdef SVC_RUN_DEBUG
1095	int i;
1096#endif
1097	register struct pollfd	*p;
1098	fd_set cleanfds;
1099
1100	for (;;) {
1101		p = pollfds;
1102		p->fd = terminate_rfd;
1103		p->events = MASKVAL;
1104		p++;
1105		for (n = 0; n <= svc_maxfd; n++) {
1106			if (FD_ISSET(n, &svc_fdset)) {
1107				p->fd = n;
1108				p->events = MASKVAL;
1109				p++;
1110			}
1111		}
1112		nfds = p - pollfds;
1113		poll_ret = 0;
1114#ifdef SVC_RUN_DEBUG
1115		if (debugging) {
1116			fprintf(stderr, "polling for read on fd < ");
1117			for (i = 0, p = pollfds; i < nfds; i++, p++)
1118				if (p->events)
1119					fprintf(stderr, "%d ", p->fd);
1120			fprintf(stderr, ">\n");
1121		}
1122#endif
1123		poll_ret = poll(pollfds, nfds, 30 * 1000);
1124
1125		if (doterminate != 0) {
1126			close(rpcbindlockfd);
1127#ifdef WARMSTART
1128			syslog(LOG_ERR,
1129			    "rpcbind terminating on signal %d. Restart with \"rpcbind -w\"",
1130			    (int)doterminate);
1131			write_warmstart();	/* Dump yourself */
1132#endif
1133			exit(2);
1134		}
1135
1136		switch (poll_ret) {
1137		case -1:
1138			/*
1139			 * We ignore all errors, continuing with the assumption
1140			 * that it was set by the signal handlers (or any
1141			 * other outside event) and not caused by poll().
1142			 */
1143		case 0:
1144			cleanfds = svc_fdset;
1145			__svc_clean_idle(&cleanfds, 30, FALSE);
1146			continue;
1147		default:
1148#ifdef SVC_RUN_DEBUG
1149			if (debugging) {
1150				fprintf(stderr, "poll returned read fds < ");
1151				for (i = 0, p = pollfds; i < nfds; i++, p++)
1152					if (p->revents)
1153						fprintf(stderr, "%d ", p->fd);
1154				fprintf(stderr, ">\n");
1155			}
1156#endif
1157			/*
1158			 * If we found as many replies on callback fds
1159			 * as the number of descriptors selectable which
1160			 * poll() returned, there can be no more so we
1161			 * don't call svc_getreq_poll.  Otherwise, there
1162			 * must be another so we must call svc_getreq_poll.
1163			 */
1164			if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
1165			    poll_ret)
1166				continue;
1167			svc_getreq_poll(pollfds, poll_ret-check_ret);
1168		}
1169#ifdef SVC_RUN_DEBUG
1170		if (debugging) {
1171			fprintf(stderr, "svc_maxfd now %u\n", svc_maxfd);
1172		}
1173#endif
1174	}
1175}
1176
1177static int
1178check_rmtcalls(struct pollfd *pfds, int nfds)
1179{
1180	int j, ncallbacks_found = 0, rmtcalls_pending;
1181	SVCXPRT *xprt;
1182
1183	if (rpcb_rmtcalls == 0)
1184		return (0);
1185
1186	rmtcalls_pending = rpcb_rmtcalls;
1187	for (j = 0; j < nfds; j++) {
1188		if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
1189			if (pfds[j].revents) {
1190				ncallbacks_found++;
1191#ifdef DEBUG_RMTCALL
1192			if (debugging)
1193				fprintf(stderr,
1194"my_svc_run:  polled on forwarding fd %d, netid %s - calling handle_reply\n",
1195		pfds[j].fd, xprt->xp_netid);
1196#endif
1197				handle_reply(pfds[j].fd, xprt);
1198				pfds[j].revents = 0;
1199				if (ncallbacks_found >= rmtcalls_pending) {
1200					break;
1201				}
1202			}
1203		}
1204	}
1205	return (ncallbacks_found);
1206}
1207
1208static void
1209xprt_set_caller(SVCXPRT *xprt, struct finfo *fi)
1210{
1211	u_int32_t *xidp;
1212
1213	netbuf_copybuf(svc_getrpccaller(xprt), fi->caller_addr);
1214	xidp = __rpcb_get_dg_xidp(xprt);
1215	*xidp = fi->caller_xid;
1216}
1217
1218/*
1219 * Call svcerr_systemerr() only if RPCBVERS4
1220 */
1221static void
1222send_svcsyserr(SVCXPRT *xprt, struct finfo *fi)
1223{
1224	if (fi->reply_type == RPCBPROC_INDIRECT) {
1225		xprt_set_caller(xprt, fi);
1226		svcerr_systemerr(xprt);
1227	}
1228	return;
1229}
1230
1231static void
1232handle_reply(int fd, SVCXPRT *xprt)
1233{
1234	XDR		reply_xdrs;
1235	struct rpc_msg	reply_msg;
1236	struct rpc_err	reply_error;
1237	char		*buffer;
1238	struct finfo	*fi;
1239	int		inlen, pos, len;
1240	struct r_rmtcall_args a;
1241	struct sockaddr_storage ss;
1242	socklen_t fromlen;
1243#ifdef SVC_RUN_DEBUG
1244	char *uaddr;
1245#endif
1246
1247	buffer = malloc(RPC_BUF_MAX);
1248	if (buffer == NULL)
1249		goto done;
1250
1251	do {
1252		fromlen = sizeof(ss);
1253		inlen = recvfrom(fd, buffer, RPC_BUF_MAX, 0,
1254			    (struct sockaddr *)&ss, &fromlen);
1255	} while (inlen < 0 && errno == EINTR);
1256	if (inlen < 0) {
1257		if (debugging)
1258			fprintf(stderr,
1259	"handle_reply:  recvfrom returned %d, errno %d\n", inlen, errno);
1260		goto done;
1261	}
1262
1263	reply_msg.acpted_rply.ar_verf = _null_auth;
1264	reply_msg.acpted_rply.ar_results.where = 0;
1265	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
1266
1267	xdrmem_create(&reply_xdrs, buffer, (u_int)inlen, XDR_DECODE);
1268	if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
1269		if (debugging)
1270			(void) fprintf(stderr,
1271				"handle_reply:  xdr_replymsg failed\n");
1272		goto done;
1273	}
1274	fi = forward_find(reply_msg.rm_xid);
1275#ifdef	SVC_RUN_DEBUG
1276	if (debugging) {
1277		fprintf(stderr, "handle_reply:  reply xid: %d fi addr: %p\n",
1278			reply_msg.rm_xid, fi);
1279	}
1280#endif
1281	if (fi == NULL) {
1282		goto done;
1283	}
1284	_seterr_reply(&reply_msg, &reply_error);
1285	if (reply_error.re_status != RPC_SUCCESS) {
1286		if (debugging)
1287			(void) fprintf(stderr, "handle_reply:  %s\n",
1288				clnt_sperrno(reply_error.re_status));
1289		send_svcsyserr(xprt, fi);
1290		goto done;
1291	}
1292	pos = XDR_GETPOS(&reply_xdrs);
1293	len = inlen - pos;
1294	a.rmt_args.args = &buffer[pos];
1295	a.rmt_args.arglen = len;
1296	a.rmt_uaddr = fi->uaddr;
1297	a.rmt_localvers = fi->versnum;
1298
1299	xprt_set_caller(xprt, fi);
1300#ifdef	SVC_RUN_DEBUG
1301	uaddr =	taddr2uaddr(rpcbind_get_conf("udp"),
1302				    svc_getrpccaller(xprt));
1303	if (debugging) {
1304		fprintf(stderr, "handle_reply:  forwarding address %s to %s\n",
1305			a.rmt_uaddr, uaddr ? uaddr : "unknown");
1306	}
1307	free(uaddr);
1308#endif
1309	svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (char *) &a);
1310done:
1311	free(buffer);
1312
1313	if (reply_msg.rm_xid == 0) {
1314#ifdef	SVC_RUN_DEBUG
1315	if (debugging) {
1316		fprintf(stderr, "handle_reply:  NULL xid on exit!\n");
1317	}
1318#endif
1319	} else
1320		(void) free_slot_by_xid(reply_msg.rm_xid);
1321	return;
1322}
1323
1324static void
1325find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
1326{
1327	register rpcblist_ptr rbl;
1328	unsigned int lowv = 0;
1329	unsigned int highv = 0;
1330
1331	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1332		if ((rbl->rpcb_map.r_prog != prog) ||
1333		    ((rbl->rpcb_map.r_netid != NULL) &&
1334			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1335			continue;
1336		if (lowv == 0) {
1337			highv = rbl->rpcb_map.r_vers;
1338			lowv = highv;
1339		} else if (rbl->rpcb_map.r_vers < lowv) {
1340			lowv = rbl->rpcb_map.r_vers;
1341		} else if (rbl->rpcb_map.r_vers > highv) {
1342			highv = rbl->rpcb_map.r_vers;
1343		}
1344	}
1345	*lowvp = lowv;
1346	*highvp = highv;
1347	return;
1348}
1349
1350/*
1351 * returns the item with the given program, version number and netid.
1352 * If that version number is not found, it returns the item with that
1353 * program number, so that address is now returned to the caller. The
1354 * caller when makes a call to this program, version number, the call
1355 * will fail and it will return with PROGVERS_MISMATCH. The user can
1356 * then determine the highest and the lowest version number for this
1357 * program using clnt_geterr() and use those program version numbers.
1358 *
1359 * Returns the RPCBLIST for the given prog, vers and netid
1360 */
1361static rpcblist_ptr
1362find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
1363{
1364	register rpcblist_ptr hit = NULL;
1365	register rpcblist_ptr rbl;
1366
1367	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1368		if ((rbl->rpcb_map.r_prog != prog) ||
1369		    ((rbl->rpcb_map.r_netid != NULL) &&
1370			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1371			continue;
1372		hit = rbl;
1373		if (rbl->rpcb_map.r_vers == vers)
1374			break;
1375	}
1376	return (hit);
1377}
1378
1379/*
1380 * Copies the name associated with the uid of the caller and returns
1381 * a pointer to it.  Similar to getwd().
1382 */
1383static char *
1384getowner(SVCXPRT *transp, char *owner, size_t ownersize)
1385{
1386	uid_t uid;
1387
1388	if (__rpc_get_local_uid(transp, &uid) < 0)
1389                strlcpy(owner, "unknown", ownersize);
1390	else if (uid == 0)
1391		strlcpy(owner, "superuser", ownersize);
1392	else
1393		snprintf(owner, ownersize, "%d", uid);
1394
1395	return owner;
1396}
1397
1398#ifdef PORTMAP
1399/*
1400 * Add this to the pmap list only if it is UDP or TCP.
1401 */
1402static int
1403add_pmaplist(RPCB *arg)
1404{
1405	struct pmap pmap;
1406	struct pmaplist *pml;
1407	int h1, h2, h3, h4, p1, p2;
1408
1409	if (strcmp(arg->r_netid, udptrans) == 0) {
1410		/* It is UDP! */
1411		pmap.pm_prot = IPPROTO_UDP;
1412	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1413		/* It is TCP */
1414		pmap.pm_prot = IPPROTO_TCP;
1415	} else
1416		/* Not an IP protocol */
1417		return (0);
1418
1419	/* interpret the universal address for TCP/IP */
1420	if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
1421		&h1, &h2, &h3, &h4, &p1, &p2) != 6)
1422		return (0);
1423	pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1424	pmap.pm_prog = arg->r_prog;
1425	pmap.pm_vers = arg->r_vers;
1426	/*
1427	 * add to END of list
1428	 */
1429	pml = malloc(sizeof (struct pmaplist));
1430	if (pml == NULL) {
1431		(void) syslog(LOG_ERR, "rpcbind: no memory!\n");
1432		return (1);
1433	}
1434	pml->pml_map = pmap;
1435	pml->pml_next = NULL;
1436	if (list_pml == NULL) {
1437		list_pml = pml;
1438	} else {
1439		struct pmaplist *fnd;
1440
1441		/* Attach to the end of the list */
1442		for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
1443			;
1444		fnd->pml_next = pml;
1445	}
1446	return (0);
1447}
1448
1449/*
1450 * Delete this from the pmap list only if it is UDP or TCP.
1451 */
1452static int
1453del_pmaplist(RPCB *arg)
1454{
1455	struct pmaplist *pml;
1456	struct pmaplist *prevpml, *fnd;
1457	unsigned long prot;
1458
1459	if (strcmp(arg->r_netid, udptrans) == 0) {
1460		/* It is UDP! */
1461		prot = IPPROTO_UDP;
1462	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1463		/* It is TCP */
1464		prot = IPPROTO_TCP;
1465	} else if (arg->r_netid[0] == 0) {
1466		prot = 0;	/* Remove all occurrences */
1467	} else {
1468		/* Not an IP protocol */
1469		return (0);
1470	}
1471	for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
1472		if ((pml->pml_map.pm_prog != arg->r_prog) ||
1473			(pml->pml_map.pm_vers != arg->r_vers) ||
1474			(prot && (pml->pml_map.pm_prot != prot))) {
1475			/* both pml & prevpml move forwards */
1476			prevpml = pml;
1477			pml = pml->pml_next;
1478			continue;
1479		}
1480		/* found it; pml moves forward, prevpml stays */
1481		fnd = pml;
1482		pml = pml->pml_next;
1483		if (prevpml == NULL)
1484			list_pml = pml;
1485		else
1486			prevpml->pml_next = pml;
1487		free(fnd);
1488	}
1489	return (0);
1490}
1491#endif /* PORTMAP */
1492