1109363Smbr/*	$NetBSD: rpcb_svc_com.c,v 1.9 2002/11/08 00:16:39 fvdl Exp $	*/
274462Salfred/*	$FreeBSD: releng/10.3/usr.sbin/rpcbind/rpcb_svc_com.c 288511 2015-10-02 16:36:16Z delphij $ */
374462Salfred
474462Salfred/*
574462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
674462Salfred * unrestricted use provided that this legend is included on all tape
774462Salfred * media and as a part of the software program in whole or part.  Users
874462Salfred * may copy or modify Sun RPC without charge, but are not authorized
974462Salfred * to license or distribute it to anyone else except as part of a product or
1074462Salfred * program developed by the user.
1174462Salfred *
1274462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1374462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1474462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1574462Salfred *
1674462Salfred * Sun RPC is provided with no support and without any obligation on the
1774462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction,
1874462Salfred * modification or enhancement.
1974462Salfred *
2074462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2174462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2274462Salfred * OR ANY PART THEREOF.
2374462Salfred *
2474462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2574462Salfred * or profits or other special, indirect and consequential damages, even if
2674462Salfred * Sun has been advised of the possibility of such damages.
2774462Salfred *
2874462Salfred * Sun Microsystems, Inc.
2974462Salfred * 2550 Garcia Avenue
3074462Salfred * Mountain View, California  94043
3174462Salfred */
3274462Salfred/*
3374462Salfred * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
3474462Salfred */
3574462Salfred
3674462Salfred/* #ident	"@(#)rpcb_svc_com.c	1.18	94/05/02 SMI" */
3774462Salfred
3874462Salfred/*
3974462Salfred * rpcb_svc_com.c
4074462Salfred * The commom server procedure for the rpcbind.
4174462Salfred */
4274462Salfred
4374462Salfred#include <sys/types.h>
4474462Salfred#include <sys/stat.h>
4574462Salfred#include <sys/param.h>
4674462Salfred#include <sys/poll.h>
4774462Salfred#include <sys/socket.h>
4874462Salfred#include <rpc/rpc.h>
4974462Salfred#include <rpc/rpcb_prot.h>
5074462Salfred#include <rpc/svc_dg.h>
51288384Sdelphij#include <assert.h>
5274462Salfred#include <netconfig.h>
5374462Salfred#include <errno.h>
5474462Salfred#include <syslog.h>
5574462Salfred#include <unistd.h>
5674462Salfred#include <stdio.h>
5774462Salfred#ifdef PORTMAP
5874462Salfred#include <netinet/in.h>
5974462Salfred#include <rpc/pmap_prot.h>
6074462Salfred#endif /* PORTMAP */
6174462Salfred#include <string.h>
6274462Salfred#include <stdlib.h>
6374462Salfred
6474462Salfred#include "rpcbind.h"
6574462Salfred
6674462Salfred#define RPC_BUF_MAX	65536	/* can be raised if required */
6774462Salfred
6874462Salfredstatic char *nullstring = "";
6974462Salfredstatic int rpcb_rmtcalls;
7074462Salfred
7174462Salfredstruct rmtcallfd_list {
7274462Salfred	int fd;
7374462Salfred	SVCXPRT *xprt;
7474462Salfred	char *netid;
7574462Salfred	struct rmtcallfd_list *next;
7674462Salfred};
7774462Salfred
7874462Salfred#define NFORWARD        64
7974462Salfred#define MAXTIME_OFF     300     /* 5 minutes */
8074462Salfred
8174462Salfredstruct finfo {
8274462Salfred	int             flag;
8374462Salfred#define FINFO_ACTIVE    0x1
8474462Salfred	u_int32_t       caller_xid;
8574462Salfred        struct netbuf   *caller_addr;
8674462Salfred	u_int32_t       forward_xid;
8774462Salfred	int             forward_fd;
8874462Salfred	char            *uaddr;
8974462Salfred	rpcproc_t       reply_type;
9074462Salfred	rpcvers_t       versnum;
9174462Salfred	time_t          time;
9274462Salfred};
9374462Salfredstatic struct finfo     FINFO[NFORWARD];
9474462Salfred
9574462Salfred
96173412Skevlostatic bool_t xdr_encap_parms(XDR *, struct encap_parms *);
97173412Skevlostatic bool_t xdr_rmtcall_args(XDR *, struct r_rmtcall_args *);
98173412Skevlostatic bool_t xdr_rmtcall_result(XDR *, struct r_rmtcall_args *);
99173412Skevlostatic bool_t xdr_opaque_parms(XDR *, struct r_rmtcall_args *);
100173412Skevlostatic int find_rmtcallfd_by_netid(char *);
101173412Skevlostatic SVCXPRT *find_rmtcallxprt_by_fd(int);
102173412Skevlostatic int forward_register(u_int32_t, struct netbuf *, int, char *,
103173412Skevlo    rpcproc_t, rpcvers_t, u_int32_t *);
104173412Skevlostatic struct finfo *forward_find(u_int32_t);
105173412Skevlostatic int free_slot_by_xid(u_int32_t);
106173412Skevlostatic int free_slot_by_index(int);
107173412Skevlostatic int netbufcmp(struct netbuf *, struct netbuf *);
108173412Skevlostatic struct netbuf *netbufdup(struct netbuf *);
109173412Skevlostatic void netbuffree(struct netbuf *);
110173412Skevlostatic int check_rmtcalls(struct pollfd *, int);
111173412Skevlostatic void xprt_set_caller(SVCXPRT *, struct finfo *);
112173412Skevlostatic void send_svcsyserr(SVCXPRT *, struct finfo *);
113173412Skevlostatic void handle_reply(int, SVCXPRT *);
114173412Skevlostatic void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
115173412Skevlostatic rpcblist_ptr find_service(rpcprog_t, rpcvers_t, char *);
116173412Skevlostatic char *getowner(SVCXPRT *, char *, size_t);
117173412Skevlostatic int add_pmaplist(RPCB *);
118173412Skevlostatic int del_pmaplist(RPCB *);
11974462Salfred
12074462Salfred/*
12174462Salfred * Set a mapping of program, version, netid
12274462Salfred */
12374462Salfred/* ARGSUSED */
12474462Salfredvoid *
125104592Salfredrpcbproc_set_com(void *arg, struct svc_req *rqstp __unused, SVCXPRT *transp,
12674462Salfred		 rpcvers_t rpcbversnum)
12774462Salfred{
12874462Salfred	RPCB *regp = (RPCB *)arg;
12974462Salfred	static bool_t ans;
13074462Salfred	char owner[64];
13174462Salfred
13274462Salfred#ifdef RPCBIND_DEBUG
13374462Salfred	if (debugging)
13474462Salfred		fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
13574462Salfred		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
13674462Salfred		    regp->r_netid, regp->r_addr);
13774462Salfred#endif
13874462Salfred	ans = map_set(regp, getowner(transp, owner, sizeof owner));
13974462Salfred#ifdef RPCBIND_DEBUG
14074462Salfred	if (debugging)
14174462Salfred		fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
14274462Salfred#endif
14374462Salfred	/* XXX: should have used some defined constant here */
14474462Salfred	rpcbs_set(rpcbversnum - 2, ans);
14574462Salfred	return (void *)&ans;
14674462Salfred}
14774462Salfred
14874462Salfredbool_t
14974462Salfredmap_set(RPCB *regp, char *owner)
15074462Salfred{
15174462Salfred	RPCB reg, *a;
15274462Salfred	rpcblist_ptr rbl, fnd;
15374462Salfred
15474462Salfred	reg = *regp;
15574462Salfred	/*
15674462Salfred	 * check to see if already used
15774462Salfred	 * find_service returns a hit even if
15874462Salfred	 * the versions don't match, so check for it
15974462Salfred	 */
16074462Salfred	fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
16174462Salfred	if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
16274462Salfred		if (!strcmp(fnd->rpcb_map.r_addr, reg.r_addr))
16374462Salfred			/*
16474462Salfred			 * if these match then it is already
16574462Salfred			 * registered so just say "OK".
16674462Salfred			 */
16774462Salfred			return (TRUE);
16874462Salfred		else
16974462Salfred			return (FALSE);
17074462Salfred	}
17174462Salfred	/*
17274462Salfred	 * add to the end of the list
17374462Salfred	 */
17496788Sjmallett	rbl = malloc(sizeof (RPCBLIST));
17596788Sjmallett	if (rbl == NULL)
17674462Salfred		return (FALSE);
17774462Salfred	a = &(rbl->rpcb_map);
17874462Salfred	a->r_prog = reg.r_prog;
17974462Salfred	a->r_vers = reg.r_vers;
18074462Salfred	a->r_netid = strdup(reg.r_netid);
18174462Salfred	a->r_addr = strdup(reg.r_addr);
18274462Salfred	a->r_owner = strdup(owner);
18374462Salfred	if (!a->r_addr || !a->r_netid || !a->r_owner) {
18474462Salfred		if (a->r_netid)
18579723Siedowse			free(a->r_netid);
18674462Salfred		if (a->r_addr)
18779723Siedowse			free(a->r_addr);
18874462Salfred		if (a->r_owner)
18979723Siedowse			free(a->r_owner);
19079723Siedowse		free(rbl);
19174462Salfred		return (FALSE);
19274462Salfred	}
19374462Salfred	rbl->rpcb_next = (rpcblist_ptr)NULL;
19474462Salfred	if (list_rbl == NULL) {
19574462Salfred		list_rbl = rbl;
19674462Salfred	} else {
19774462Salfred		for (fnd = list_rbl; fnd->rpcb_next;
19874462Salfred			fnd = fnd->rpcb_next)
19974462Salfred			;
20074462Salfred		fnd->rpcb_next = rbl;
20174462Salfred	}
20274462Salfred#ifdef PORTMAP
20374462Salfred	(void) add_pmaplist(regp);
20474462Salfred#endif
20574462Salfred	return (TRUE);
20674462Salfred}
20774462Salfred
20874462Salfred/*
20974462Salfred * Unset a mapping of program, version, netid
21074462Salfred */
21174462Salfred/* ARGSUSED */
21274462Salfredvoid *
213104592Salfredrpcbproc_unset_com(void *arg, struct svc_req *rqstp __unused, SVCXPRT *transp,
21474462Salfred		   rpcvers_t rpcbversnum)
21574462Salfred{
21674462Salfred	RPCB *regp = (RPCB *)arg;
21774462Salfred	static bool_t ans;
21874462Salfred	char owner[64];
21974462Salfred
22074462Salfred#ifdef RPCBIND_DEBUG
22174462Salfred	if (debugging)
22274462Salfred		fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
22374462Salfred		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
22474462Salfred		    regp->r_netid);
22574462Salfred#endif
22674462Salfred	ans = map_unset(regp, getowner(transp, owner, sizeof owner));
22774462Salfred#ifdef RPCBIND_DEBUG
22874462Salfred	if (debugging)
22974462Salfred		fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
23074462Salfred#endif
23174462Salfred	/* XXX: should have used some defined constant here */
23274462Salfred	rpcbs_unset(rpcbversnum - 2, ans);
23374462Salfred	return (void *)&ans;
23474462Salfred}
23574462Salfred
23674462Salfredbool_t
23774462Salfredmap_unset(RPCB *regp, char *owner)
23874462Salfred{
23974462Salfred	int ans = 0;
24074462Salfred	rpcblist_ptr rbl, prev, tmp;
24174462Salfred
24274462Salfred	if (owner == NULL)
24374462Salfred		return (0);
24474462Salfred
24574462Salfred	for (prev = NULL, rbl = list_rbl; rbl; /* cstyle */) {
24674462Salfred		if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
24774462Salfred			(rbl->rpcb_map.r_vers != regp->r_vers) ||
24874462Salfred			(regp->r_netid[0] && strcasecmp(regp->r_netid,
24974462Salfred				rbl->rpcb_map.r_netid))) {
25074462Salfred			/* both rbl & prev move forwards */
25174462Salfred			prev = rbl;
25274462Salfred			rbl = rbl->rpcb_next;
25374462Salfred			continue;
25474462Salfred		}
25574462Salfred		/*
25674462Salfred		 * Check whether appropriate uid. Unset only
25774462Salfred		 * if superuser or the owner itself.
25874462Salfred		 */
25974462Salfred		if (strcmp(owner, "superuser") &&
26074462Salfred			strcmp(rbl->rpcb_map.r_owner, owner))
26174462Salfred			return (0);
26274462Salfred		/* found it; rbl moves forward, prev stays */
26374462Salfred		ans = 1;
26474462Salfred		tmp = rbl;
26574462Salfred		rbl = rbl->rpcb_next;
26674462Salfred		if (prev == NULL)
26774462Salfred			list_rbl = rbl;
26874462Salfred		else
26974462Salfred			prev->rpcb_next = rbl;
27079723Siedowse		free(tmp->rpcb_map.r_addr);
27179723Siedowse		free(tmp->rpcb_map.r_netid);
27279723Siedowse		free(tmp->rpcb_map.r_owner);
27379723Siedowse		free(tmp);
27474462Salfred	}
27574462Salfred#ifdef PORTMAP
27674462Salfred	if (ans)
27774462Salfred		(void) del_pmaplist(regp);
27874462Salfred#endif
27974462Salfred	/*
28074462Salfred	 * We return 1 either when the entry was not there or it
28174462Salfred	 * was able to unset it.  It can come to this point only if
28274462Salfred	 * atleast one of the conditions is true.
28374462Salfred	 */
28474462Salfred	return (1);
28574462Salfred}
28674462Salfred
28774462Salfredvoid
288104592Salfreddelete_prog(unsigned int prog)
28974462Salfred{
29074462Salfred	RPCB reg;
29174462Salfred	register rpcblist_ptr rbl;
29274462Salfred
29374462Salfred	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
29474462Salfred		if ((rbl->rpcb_map.r_prog != prog))
29574462Salfred			continue;
29674462Salfred		if (is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr))
29774462Salfred			continue;
29874462Salfred		reg.r_prog = rbl->rpcb_map.r_prog;
29974462Salfred		reg.r_vers = rbl->rpcb_map.r_vers;
30074462Salfred		reg.r_netid = strdup(rbl->rpcb_map.r_netid);
30174462Salfred		(void) map_unset(&reg, "superuser");
30274462Salfred		free(reg.r_netid);
30374462Salfred	}
30474462Salfred}
30574462Salfred
30674462Salfredvoid *
307104592Salfredrpcbproc_getaddr_com(RPCB *regp, struct svc_req *rqstp __unused,
308104592Salfred		     SVCXPRT *transp, rpcvers_t rpcbversnum, rpcvers_t verstype)
30974462Salfred{
31074462Salfred	static char *uaddr;
31174462Salfred	char *saddr = NULL;
31274462Salfred	rpcblist_ptr fnd;
31374462Salfred
31479723Siedowse	if (uaddr != NULL && uaddr != nullstring) {
31579723Siedowse		free(uaddr);
31679723Siedowse		uaddr = NULL;
31779723Siedowse	}
31874462Salfred	fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
31974462Salfred	if (fnd && ((verstype == RPCB_ALLVERS) ||
32074462Salfred		    (regp->r_vers == fnd->rpcb_map.r_vers))) {
32174462Salfred		if (*(regp->r_addr) != '\0') {  /* may contain a hint about */
32274462Salfred			saddr = regp->r_addr;   /* the interface that we    */
32374462Salfred		}				/* should use */
32474462Salfred		if (!(uaddr = mergeaddr(transp, transp->xp_netid,
32574462Salfred				fnd->rpcb_map.r_addr, saddr))) {
32674462Salfred			/* Try whatever we have */
32774462Salfred			uaddr = strdup(fnd->rpcb_map.r_addr);
32874462Salfred		} else if (!uaddr[0]) {
32974462Salfred			/*
33074462Salfred			 * The server died.  Unset all versions of this prog.
33174462Salfred			 */
33274462Salfred			delete_prog(regp->r_prog);
33374462Salfred			uaddr = nullstring;
33474462Salfred		}
33574462Salfred	} else {
33674462Salfred		uaddr = nullstring;
33774462Salfred	}
33874462Salfred#ifdef RPCBIND_DEBUG
33974462Salfred	if (debugging)
34074462Salfred		fprintf(stderr, "getaddr: %s\n", uaddr);
34174462Salfred#endif
34274462Salfred	/* XXX: should have used some defined constant here */
34374462Salfred	rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers,
34474462Salfred		transp->xp_netid, uaddr);
34574462Salfred	return (void *)&uaddr;
34674462Salfred}
34774462Salfred
34874462Salfred/* ARGSUSED */
34974462Salfredvoid *
350104592Salfredrpcbproc_gettime_com(void *arg __unused, struct svc_req *rqstp __unused,
351104592Salfred		     SVCXPRT *transp __unused, rpcvers_t rpcbversnum __unused)
35274462Salfred{
35374462Salfred	static time_t curtime;
35474462Salfred
35574462Salfred	(void) time(&curtime);
35674462Salfred	return (void *)&curtime;
35774462Salfred}
35874462Salfred
35974462Salfred/*
36074462Salfred * Convert uaddr to taddr. Should be used only by
36174462Salfred * local servers/clients. (kernel level stuff only)
36274462Salfred */
36374462Salfred/* ARGSUSED */
36474462Salfredvoid *
365104592Salfredrpcbproc_uaddr2taddr_com(void *arg, struct svc_req *rqstp __unused,
366104592Salfred			 SVCXPRT *transp, rpcvers_t rpcbversnum __unused)
36774462Salfred{
36874462Salfred	char **uaddrp = (char **)arg;
36974462Salfred	struct netconfig *nconf;
37074462Salfred	static struct netbuf nbuf;
37174462Salfred	static struct netbuf *taddr;
37274462Salfred
37374462Salfred	if (taddr) {
37479723Siedowse		free(taddr->buf);
37579723Siedowse		free(taddr);
37679723Siedowse		taddr = NULL;
37774462Salfred	}
37874462Salfred	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
37974462Salfred	    ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
38074462Salfred		(void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
38174462Salfred		return (void *)&nbuf;
38274462Salfred	}
38374462Salfred	return (void *)taddr;
38474462Salfred}
38574462Salfred
38674462Salfred/*
38774462Salfred * Convert taddr to uaddr. Should be used only by
38874462Salfred * local servers/clients. (kernel level stuff only)
38974462Salfred */
39074462Salfred/* ARGSUSED */
39174462Salfredvoid *
392104592Salfredrpcbproc_taddr2uaddr_com(void *arg, struct svc_req *rqstp __unused,
393104592Salfred			 SVCXPRT *transp, rpcvers_t rpcbversnum __unused)
39474462Salfred{
39574462Salfred	struct netbuf *taddr = (struct netbuf *)arg;
39674462Salfred	static char *uaddr;
39774462Salfred	struct netconfig *nconf;
39874462Salfred
39974462Salfred#ifdef CHEW_FDS
40074462Salfred	int fd;
40174462Salfred
40274462Salfred	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
40374462Salfred		uaddr = (char *)strerror(errno);
40474462Salfred		return (&uaddr);
40574462Salfred	}
40674462Salfred#endif /* CHEW_FDS */
40779723Siedowse	if (uaddr != NULL && uaddr != nullstring) {
40879723Siedowse		free(uaddr);
40979723Siedowse		uaddr = NULL;
41079723Siedowse	}
41174462Salfred	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
41274462Salfred		((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
41374462Salfred		uaddr = nullstring;
41474462Salfred	}
41574462Salfred	return (void *)&uaddr;
41674462Salfred}
41774462Salfred
41874462Salfred
41974462Salfredstatic bool_t
42074462Salfredxdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
42174462Salfred{
42274462Salfred	return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen), ~0));
42374462Salfred}
42474462Salfred
42574462Salfred/*
42674462Salfred * XDR remote call arguments.  It ignores the address part.
42774462Salfred * written for XDR_DECODE direction only
42874462Salfred */
42974462Salfredstatic bool_t
43074462Salfredxdr_rmtcall_args(XDR *xdrs, struct r_rmtcall_args *cap)
43174462Salfred{
43274462Salfred	/* does not get the address or the arguments */
43374462Salfred	if (xdr_u_int32_t(xdrs, &(cap->rmt_prog)) &&
43474462Salfred	    xdr_u_int32_t(xdrs, &(cap->rmt_vers)) &&
43574462Salfred	    xdr_u_int32_t(xdrs, &(cap->rmt_proc))) {
43674462Salfred		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
43774462Salfred	}
43874462Salfred	return (FALSE);
43974462Salfred}
44074462Salfred
44174462Salfred/*
44274462Salfred * XDR remote call results along with the address.  Ignore
44374462Salfred * program number, version  number and proc number.
44474462Salfred * Written for XDR_ENCODE direction only.
44574462Salfred */
44674462Salfredstatic bool_t
44774462Salfredxdr_rmtcall_result(XDR *xdrs, struct r_rmtcall_args *cap)
44874462Salfred{
44974462Salfred	bool_t result;
45074462Salfred
45174462Salfred#ifdef PORTMAP
45274462Salfred	if (cap->rmt_localvers == PMAPVERS) {
45374462Salfred		int h1, h2, h3, h4, p1, p2;
45474462Salfred		u_long port;
45574462Salfred
45674462Salfred		/* interpret the universal address for TCP/IP */
45774462Salfred		if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
45874462Salfred			&h1, &h2, &h3, &h4, &p1, &p2) != 6)
45974462Salfred			return (FALSE);
46074462Salfred		port = ((p1 & 0xff) << 8) + (p2 & 0xff);
46174462Salfred		result = xdr_u_long(xdrs, &port);
46274462Salfred	} else
46374462Salfred#endif
46474462Salfred		if ((cap->rmt_localvers == RPCBVERS) ||
46574462Salfred		    (cap->rmt_localvers == RPCBVERS4)) {
46674462Salfred		result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
46774462Salfred	} else {
46874462Salfred		return (FALSE);
46974462Salfred	}
47074462Salfred	if (result == TRUE)
47174462Salfred		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
47274462Salfred	return (FALSE);
47374462Salfred}
47474462Salfred
47574462Salfred/*
47674462Salfred * only worries about the struct encap_parms part of struct r_rmtcall_args.
47774462Salfred * The arglen must already be set!!
47874462Salfred */
47974462Salfredstatic bool_t
48074462Salfredxdr_opaque_parms(XDR *xdrs, struct r_rmtcall_args *cap)
48174462Salfred{
48274462Salfred	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
48374462Salfred}
48474462Salfred
48574462Salfredstatic struct rmtcallfd_list *rmthead;
48674462Salfredstatic struct rmtcallfd_list *rmttail;
48774462Salfred
48874462Salfredint
48974462Salfredcreate_rmtcall_fd(struct netconfig *nconf)
49074462Salfred{
49174462Salfred	int fd;
49274462Salfred	struct rmtcallfd_list *rmt;
49374462Salfred	SVCXPRT *xprt;
49474462Salfred
49574462Salfred	if ((fd = __rpc_nconf2fd(nconf)) == -1) {
49674462Salfred		if (debugging)
49774462Salfred			fprintf(stderr,
49874462Salfred	"create_rmtcall_fd: couldn't open \"%s\" (errno %d)\n",
49974462Salfred			nconf->nc_device, errno);
50074462Salfred		return (-1);
50174462Salfred	}
50274462Salfred	xprt = svc_tli_create(fd, 0, (struct t_bind *) 0, 0, 0);
50374462Salfred	if (xprt == NULL) {
50474462Salfred		if (debugging)
50574462Salfred			fprintf(stderr,
50674462Salfred				"create_rmtcall_fd: svc_tli_create failed\n");
50774462Salfred		return (-1);
50874462Salfred	}
50996788Sjmallett	rmt = malloc(sizeof (struct rmtcallfd_list));
51074462Salfred	if (rmt == NULL) {
51174462Salfred		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
51274462Salfred		return (-1);
51374462Salfred	}
51474462Salfred	rmt->xprt = xprt;
51574462Salfred	rmt->netid = strdup(nconf->nc_netid);
51674462Salfred	xprt->xp_netid = rmt->netid;
51774462Salfred	rmt->fd = fd;
51874462Salfred	rmt->next = NULL;
51974462Salfred	if (rmthead == NULL) {
52074462Salfred		rmthead = rmt;
52174462Salfred		rmttail = rmt;
52274462Salfred	} else {
52374462Salfred		rmttail->next = rmt;
52474462Salfred		rmttail = rmt;
52574462Salfred	}
52674462Salfred	/* XXX not threadsafe */
52774462Salfred	if (fd > svc_maxfd)
52874462Salfred		svc_maxfd = fd;
52974462Salfred	FD_SET(fd, &svc_fdset);
53074462Salfred	return (fd);
53174462Salfred}
53274462Salfred
53374462Salfredstatic int
53474462Salfredfind_rmtcallfd_by_netid(char *netid)
53574462Salfred{
53674462Salfred	struct rmtcallfd_list *rmt;
53774462Salfred
53874462Salfred	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
53974462Salfred		if (strcmp(netid, rmt->netid) == 0) {
54074462Salfred			return (rmt->fd);
54174462Salfred		}
54274462Salfred	}
54374462Salfred	return (-1);
54474462Salfred}
54574462Salfred
54674462Salfredstatic SVCXPRT *
54774462Salfredfind_rmtcallxprt_by_fd(int fd)
54874462Salfred{
54974462Salfred	struct rmtcallfd_list *rmt;
55074462Salfred
55174462Salfred	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
55274462Salfred		if (fd == rmt->fd) {
55374462Salfred			return (rmt->xprt);
55474462Salfred		}
55574462Salfred	}
55674462Salfred	return (NULL);
55774462Salfred}
55874462Salfred
55974462Salfred
56074462Salfred/*
56174462Salfred * Call a remote procedure service.  This procedure is very quiet when things
56274462Salfred * go wrong.  The proc is written to support broadcast rpc.  In the broadcast
56374462Salfred * case, a machine should shut-up instead of complain, lest the requestor be
56474462Salfred * overrun with complaints at the expense of not hearing a valid reply.
56574462Salfred * When receiving a request and verifying that the service exists, we
56674462Salfred *
56774462Salfred *	receive the request
56874462Salfred *
56974462Salfred *	open a new TLI endpoint on the same transport on which we received
57074462Salfred *	the original request
57174462Salfred *
57274462Salfred *	remember the original request's XID (which requires knowing the format
57374462Salfred *	of the svc_dg_data structure)
57474462Salfred *
57574462Salfred *	forward the request, with a new XID, to the requested service,
57674462Salfred *	remembering the XID used to send this request (for later use in
57774462Salfred *	reassociating the answer with the original request), the requestor's
57874462Salfred *	address, the file descriptor on which the forwarded request is
57974462Salfred *	made and the service's address.
58074462Salfred *
58174462Salfred *	mark the file descriptor on which we anticipate receiving a reply from
58274462Salfred *	the service and one to select for in our private svc_run procedure
58374462Salfred *
58474462Salfred * At some time in the future, a reply will be received from the service to
58574462Salfred * which we forwarded the request.  At that time, we detect that the socket
58674462Salfred * used was for forwarding (by looking through the finfo structures to see
58774462Salfred * whether the fd corresponds to one of those) and call handle_reply() to
58874462Salfred *
58974462Salfred *	receive the reply
59074462Salfred *
59174462Salfred *	bundle the reply, along with the service's universal address
59274462Salfred *
59374462Salfred *	create a SVCXPRT structure and use a version of svc_sendreply
59474462Salfred *	that allows us to specify the reply XID and destination, send the reply
59574462Salfred *	to the original requestor.
59674462Salfred */
59774462Salfred
59874462Salfredvoid
59974462Salfredrpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp,
60074462Salfred		    rpcproc_t reply_type, rpcvers_t versnum)
60174462Salfred{
60274462Salfred	register rpcblist_ptr rbl;
60374462Salfred	struct netconfig *nconf;
60474462Salfred	struct netbuf *caller;
60574462Salfred	struct r_rmtcall_args a;
60674462Salfred	char *buf_alloc = NULL, *outbufp;
60774462Salfred	char *outbuf_alloc = NULL;
60874462Salfred	char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
60974462Salfred	struct netbuf *na = (struct netbuf *) NULL;
61074462Salfred	struct rpc_msg call_msg;
61174462Salfred	int outlen;
61274462Salfred	u_int sendsz;
61374462Salfred	XDR outxdr;
61474462Salfred	AUTH *auth;
61574462Salfred	int fd = -1;
61679723Siedowse	char *uaddr, *m_uaddr = NULL, *local_uaddr = NULL;
61774462Salfred	u_int32_t *xidp;
61874462Salfred	struct __rpc_sockinfo si;
61974462Salfred	struct sockaddr *localsa;
62074462Salfred	struct netbuf tbuf;
62174462Salfred
62274462Salfred	if (!__rpc_fd2sockinfo(transp->xp_fd, &si)) {
62374462Salfred		if (reply_type == RPCBPROC_INDIRECT)
62474462Salfred			svcerr_systemerr(transp);
62574462Salfred		return;
62674462Salfred	}
62774462Salfred	if (si.si_socktype != SOCK_DGRAM)
62874462Salfred		return;	/* Only datagram type accepted */
62974462Salfred	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, UDPMSGSIZE);
63074462Salfred	if (sendsz == 0) {	/* data transfer not supported */
63174462Salfred		if (reply_type == RPCBPROC_INDIRECT)
63274462Salfred			svcerr_systemerr(transp);
63374462Salfred		return;
63474462Salfred	}
63574462Salfred	/*
63674462Salfred	 * Should be multiple of 4 for XDR.
63774462Salfred	 */
63874462Salfred	sendsz = ((sendsz + 3) / 4) * 4;
63974462Salfred	if (sendsz > RPC_BUF_MAX) {
64074462Salfred#ifdef	notyet
64174462Salfred		buf_alloc = alloca(sendsz);		/* not in IDR2? */
64274462Salfred#else
64374462Salfred		buf_alloc = malloc(sendsz);
64474462Salfred#endif	/* notyet */
64574462Salfred		if (buf_alloc == NULL) {
64674462Salfred			if (debugging)
64774462Salfred				fprintf(stderr,
64874462Salfred					"rpcbproc_callit_com:  No Memory!\n");
64974462Salfred			if (reply_type == RPCBPROC_INDIRECT)
65074462Salfred				svcerr_systemerr(transp);
65174462Salfred			return;
65274462Salfred		}
65374462Salfred		a.rmt_args.args = buf_alloc;
65474462Salfred	} else {
65574462Salfred		a.rmt_args.args = buf;
65674462Salfred	}
65774462Salfred
65874462Salfred	call_msg.rm_xid = 0;	/* For error checking purposes */
65974462Salfred	if (!svc_getargs(transp, (xdrproc_t) xdr_rmtcall_args, (char *) &a)) {
66074462Salfred		if (reply_type == RPCBPROC_INDIRECT)
66174462Salfred			svcerr_decode(transp);
66274462Salfred		if (debugging)
66374462Salfred			fprintf(stderr,
66474462Salfred			"rpcbproc_callit_com:  svc_getargs failed\n");
66574462Salfred		goto error;
66674462Salfred	}
66774462Salfred
66874462Salfred	if (!check_callit(transp, &a, versnum)) {
66974462Salfred		svcerr_weakauth(transp);
67074462Salfred		goto error;
67174462Salfred	}
67274462Salfred
67374462Salfred	caller = svc_getrpccaller(transp);
67474462Salfred#ifdef RPCBIND_DEBUG
67574462Salfred	if (debugging) {
67674462Salfred		uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
67774462Salfred		fprintf(stderr, "%s %s req for (%lu, %lu, %lu, %s) from %s : ",
67874462Salfred			versnum == PMAPVERS ? "pmap_rmtcall" :
67974462Salfred			versnum == RPCBVERS ? "rpcb_rmtcall" :
68074462Salfred			versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
68174462Salfred			reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
68274462Salfred			(unsigned long)a.rmt_prog, (unsigned long)a.rmt_vers,
68374462Salfred			(unsigned long)a.rmt_proc, transp->xp_netid,
68474462Salfred			uaddr ? uaddr : "unknown");
68574462Salfred		if (uaddr)
68679723Siedowse			free(uaddr);
68774462Salfred	}
68874462Salfred#endif
68974462Salfred
69074462Salfred	rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
69174462Salfred
69274462Salfred	rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
69374462Salfred			a.rmt_proc, transp->xp_netid, rbl);
69474462Salfred
69574462Salfred	if (rbl == (rpcblist_ptr)NULL) {
69674462Salfred#ifdef RPCBIND_DEBUG
69774462Salfred		if (debugging)
69874462Salfred			fprintf(stderr, "not found\n");
69974462Salfred#endif
70074462Salfred		if (reply_type == RPCBPROC_INDIRECT)
70174462Salfred			svcerr_noprog(transp);
70274462Salfred		goto error;
70374462Salfred	}
70474462Salfred	if (rbl->rpcb_map.r_vers != a.rmt_vers) {
70574462Salfred		if (reply_type == RPCBPROC_INDIRECT) {
70674462Salfred			rpcvers_t vers_low, vers_high;
70774462Salfred
70874462Salfred			find_versions(a.rmt_prog, transp->xp_netid,
70974462Salfred				&vers_low, &vers_high);
71074462Salfred			svcerr_progvers(transp, vers_low, vers_high);
71174462Salfred		}
71274462Salfred		goto error;
71374462Salfred	}
71474462Salfred
71574462Salfred#ifdef RPCBIND_DEBUG
71674462Salfred	if (debugging)
71774462Salfred		fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
71874462Salfred#endif
71974462Salfred	/*
72074462Salfred	 *	Check whether this entry is valid and a server is present
72174462Salfred	 *	Mergeaddr() returns NULL if no such entry is present, and
72274462Salfred	 *	returns "" if the entry was present but the server is not
72374462Salfred	 *	present (i.e., it crashed).
72474462Salfred	 */
72574462Salfred	if (reply_type == RPCBPROC_INDIRECT) {
72674462Salfred		uaddr = mergeaddr(transp, transp->xp_netid,
72774462Salfred			rbl->rpcb_map.r_addr, NULL);
72879723Siedowse		if (uaddr == NULL || uaddr[0] == '\0') {
72974462Salfred			svcerr_noprog(transp);
73079723Siedowse			if (uaddr != NULL)
73179723Siedowse				free(uaddr);
73274462Salfred			goto error;
73374462Salfred		}
73479723Siedowse		free(uaddr);
73574462Salfred	}
73674462Salfred	nconf = rpcbind_get_conf(transp->xp_netid);
73774462Salfred	if (nconf == (struct netconfig *)NULL) {
73874462Salfred		if (reply_type == RPCBPROC_INDIRECT)
73974462Salfred			svcerr_systemerr(transp);
74074462Salfred		if (debugging)
74174462Salfred			fprintf(stderr,
74274462Salfred			"rpcbproc_callit_com:  rpcbind_get_conf failed\n");
74374462Salfred		goto error;
74474462Salfred	}
74574462Salfred	localsa = local_sa(((struct sockaddr *)caller->buf)->sa_family);
74674462Salfred	if (localsa == NULL) {
74774462Salfred		if (debugging)
74874462Salfred			fprintf(stderr,
74974462Salfred			"rpcbproc_callit_com: no local address\n");
75074462Salfred		goto error;
75174462Salfred	}
75274462Salfred	tbuf.len = tbuf.maxlen = localsa->sa_len;
75374462Salfred	tbuf.buf = localsa;
75474462Salfred	local_uaddr =
75574462Salfred	    addrmerge(&tbuf, rbl->rpcb_map.r_addr, NULL, nconf->nc_netid);
75674462Salfred	m_uaddr = addrmerge(caller, rbl->rpcb_map.r_addr, NULL,
75774462Salfred			nconf->nc_netid);
75874462Salfred#ifdef RPCBIND_DEBUG
75974462Salfred	if (debugging)
76074462Salfred		fprintf(stderr, "merged uaddr %s\n", m_uaddr);
76174462Salfred#endif
76274462Salfred	if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
76374462Salfred		if (reply_type == RPCBPROC_INDIRECT)
76474462Salfred			svcerr_systemerr(transp);
76574462Salfred		goto error;
76674462Salfred	}
76774462Salfred	xidp = __rpcb_get_dg_xidp(transp);
76878681Siedowse	switch (forward_register(*xidp, caller, fd, m_uaddr, reply_type,
76978681Siedowse	    versnum, &call_msg.rm_xid)) {
77078681Siedowse	case 1:
77178681Siedowse		/* Success; forward_register() will free m_uaddr for us. */
77278681Siedowse		m_uaddr = NULL;
77378681Siedowse		break;
77478681Siedowse	case 0:
77574462Salfred		/*
77674462Salfred		 * A duplicate request for the slow server.  Let's not
77774462Salfred		 * beat on it any more.
77874462Salfred		 */
77974462Salfred		if (debugging)
78074462Salfred			fprintf(stderr,
78174462Salfred			"rpcbproc_callit_com:  duplicate request\n");
78274462Salfred		goto error;
78378681Siedowse	case -1:
78474462Salfred		/*  forward_register failed.  Perhaps no memory. */
78574462Salfred		if (debugging)
78674462Salfred			fprintf(stderr,
78774462Salfred			"rpcbproc_callit_com:  forward_register failed\n");
78874462Salfred		goto error;
78974462Salfred	}
79074462Salfred
79174462Salfred#ifdef DEBUG_RMTCALL
79274462Salfred	if (debugging)
79374462Salfred		fprintf(stderr,
79474462Salfred			"rpcbproc_callit_com:  original XID %x, new XID %x\n",
79574462Salfred				*xidp, call_msg.rm_xid);
79674462Salfred#endif
79774462Salfred	call_msg.rm_direction = CALL;
79874462Salfred	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
79974462Salfred	call_msg.rm_call.cb_prog = a.rmt_prog;
80074462Salfred	call_msg.rm_call.cb_vers = a.rmt_vers;
80174462Salfred	if (sendsz > RPC_BUF_MAX) {
80274462Salfred#ifdef	notyet
80374462Salfred		outbuf_alloc = alloca(sendsz);	/* not in IDR2? */
80474462Salfred#else
80574462Salfred		outbuf_alloc = malloc(sendsz);
80674462Salfred#endif	/* notyet */
80774462Salfred		if (outbuf_alloc == NULL) {
80874462Salfred			if (reply_type == RPCBPROC_INDIRECT)
80974462Salfred				svcerr_systemerr(transp);
81074462Salfred			if (debugging)
81174462Salfred				fprintf(stderr,
81274462Salfred				"rpcbproc_callit_com:  No memory!\n");
81374462Salfred			goto error;
81474462Salfred		}
81574462Salfred		xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
81674462Salfred	} else {
81774462Salfred		xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
81874462Salfred	}
81974462Salfred	if (!xdr_callhdr(&outxdr, &call_msg)) {
82074462Salfred		if (reply_type == RPCBPROC_INDIRECT)
82174462Salfred			svcerr_systemerr(transp);
82274462Salfred		if (debugging)
82374462Salfred			fprintf(stderr,
82474462Salfred			"rpcbproc_callit_com:  xdr_callhdr failed\n");
82574462Salfred		goto error;
82674462Salfred	}
82774462Salfred	if (!xdr_u_int32_t(&outxdr, &(a.rmt_proc))) {
82874462Salfred		if (reply_type == RPCBPROC_INDIRECT)
82974462Salfred			svcerr_systemerr(transp);
83074462Salfred		if (debugging)
83174462Salfred			fprintf(stderr,
83274462Salfred			"rpcbproc_callit_com:  xdr_u_long failed\n");
83374462Salfred		goto error;
83474462Salfred	}
83574462Salfred
83674462Salfred	if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
83774462Salfred		auth = authnone_create();
83874462Salfred	} else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
83974462Salfred		struct authunix_parms *au;
84074462Salfred
84174462Salfred		au = (struct authunix_parms *)rqstp->rq_clntcred;
84274462Salfred		auth = authunix_create(au->aup_machname,
84374462Salfred				au->aup_uid, au->aup_gid,
84474462Salfred				au->aup_len, au->aup_gids);
84574462Salfred		if (auth == NULL) /* fall back */
84674462Salfred			auth = authnone_create();
84774462Salfred	} else {
84874462Salfred		/* we do not support any other authentication scheme */
84974462Salfred		if (debugging)
85074462Salfred			fprintf(stderr,
85174462Salfred"rpcbproc_callit_com:  oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
85274462Salfred		if (reply_type == RPCBPROC_INDIRECT)
85374462Salfred			svcerr_weakauth(transp); /* XXX too strong.. */
85474462Salfred		goto error;
85574462Salfred	}
85674462Salfred	if (auth == NULL) {
85774462Salfred		if (reply_type == RPCBPROC_INDIRECT)
85874462Salfred			svcerr_systemerr(transp);
85974462Salfred		if (debugging)
86074462Salfred			fprintf(stderr,
86174462Salfred		"rpcbproc_callit_com:  authwhatever_create returned NULL\n");
86274462Salfred		goto error;
86374462Salfred	}
86474462Salfred	if (!AUTH_MARSHALL(auth, &outxdr)) {
86574462Salfred		if (reply_type == RPCBPROC_INDIRECT)
86674462Salfred			svcerr_systemerr(transp);
86774462Salfred		AUTH_DESTROY(auth);
86874462Salfred		if (debugging)
86974462Salfred			fprintf(stderr,
87074462Salfred		"rpcbproc_callit_com:  AUTH_MARSHALL failed\n");
87174462Salfred		goto error;
87274462Salfred	}
87374462Salfred	AUTH_DESTROY(auth);
87474462Salfred	if (!xdr_opaque_parms(&outxdr, &a)) {
87574462Salfred		if (reply_type == RPCBPROC_INDIRECT)
87674462Salfred			svcerr_systemerr(transp);
87774462Salfred		if (debugging)
87874462Salfred			fprintf(stderr,
87974462Salfred		"rpcbproc_callit_com:  xdr_opaque_parms failed\n");
88074462Salfred		goto error;
88174462Salfred	}
88274462Salfred	outlen = (int) XDR_GETPOS(&outxdr);
88374462Salfred	if (outbuf_alloc)
88474462Salfred		outbufp = outbuf_alloc;
88574462Salfred	else
88674462Salfred		outbufp = outbuf;
88774462Salfred
88874462Salfred	na = uaddr2taddr(nconf, local_uaddr);
88974462Salfred	if (!na) {
89074462Salfred		if (reply_type == RPCBPROC_INDIRECT)
89174462Salfred			svcerr_systemerr(transp);
89274462Salfred		goto error;
89374462Salfred	}
89474462Salfred
89574462Salfred	if (sendto(fd, outbufp, outlen, 0, (struct sockaddr *)na->buf, na->len)
89674462Salfred	    != outlen) {
89774462Salfred		if (debugging)
89874462Salfred			fprintf(stderr,
89974462Salfred	"rpcbproc_callit_com:  sendto failed:  errno %d\n", errno);
90074462Salfred		if (reply_type == RPCBPROC_INDIRECT)
90174462Salfred			svcerr_systemerr(transp);
90274462Salfred		goto error;
90374462Salfred	}
90474462Salfred	goto out;
90574462Salfred
90674462Salfrederror:
90774462Salfred	if (call_msg.rm_xid != 0)
90874462Salfred		(void) free_slot_by_xid(call_msg.rm_xid);
90974462Salfredout:
91074462Salfred	if (local_uaddr)
91174462Salfred		free(local_uaddr);
91274462Salfred	if (buf_alloc)
91379723Siedowse		free(buf_alloc);
91474462Salfred	if (outbuf_alloc)
91579723Siedowse		free(outbuf_alloc);
91674462Salfred	if (na) {
91774462Salfred		free(na->buf);
91874462Salfred		free(na);
91974462Salfred	}
92079723Siedowse	if (m_uaddr != NULL)
92179723Siedowse		free(m_uaddr);
92274462Salfred}
92374462Salfred
92474462Salfred/*
92574462Salfred * Makes an entry into the FIFO for the given request.
92678681Siedowse * Returns 1 on success, 0 if this is a duplicate request, or -1 on error.
92778681Siedowse * *callxidp is set to the xid of the call.
92874462Salfred */
92978681Siedowsestatic int
93074462Salfredforward_register(u_int32_t caller_xid, struct netbuf *caller_addr,
93174462Salfred		 int forward_fd, char *uaddr, rpcproc_t reply_type,
93278681Siedowse		 rpcvers_t versnum, u_int32_t *callxidp)
93374462Salfred{
93474462Salfred	int		i;
93574462Salfred	int		j = 0;
93674462Salfred	time_t		min_time, time_now;
93774462Salfred	static u_int32_t	lastxid;
93874462Salfred	int		entry = -1;
93974462Salfred
94074462Salfred	min_time = FINFO[0].time;
94174462Salfred	time_now = time((time_t *)0);
94274462Salfred	/* initialization */
94374462Salfred	if (lastxid == 0)
94474462Salfred		lastxid = time_now * NFORWARD;
94574462Salfred
94674462Salfred	/*
947108470Sschweikh	 * Check if it is a duplicate entry. Then,
94874462Salfred	 * try to find an empty slot.  If not available, then
94974462Salfred	 * use the slot with the earliest time.
95074462Salfred	 */
95174462Salfred	for (i = 0; i < NFORWARD; i++) {
95274462Salfred		if (FINFO[i].flag & FINFO_ACTIVE) {
95374462Salfred			if ((FINFO[i].caller_xid == caller_xid) &&
95474462Salfred			    (FINFO[i].reply_type == reply_type) &&
95574462Salfred			    (FINFO[i].versnum == versnum) &&
95674462Salfred			    (!netbufcmp(FINFO[i].caller_addr,
95774462Salfred					    caller_addr))) {
95874462Salfred				FINFO[i].time = time((time_t *)0);
95974462Salfred				return (0);	/* Duplicate entry */
96074462Salfred			} else {
96174462Salfred				/* Should we wait any longer */
96274462Salfred				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
96374462Salfred					(void) free_slot_by_index(i);
96474462Salfred			}
96574462Salfred		}
96674462Salfred		if (entry == -1) {
96774462Salfred			if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
96874462Salfred				entry = i;
96974462Salfred			} else if (FINFO[i].time < min_time) {
97074462Salfred				j = i;
97174462Salfred				min_time = FINFO[i].time;
97274462Salfred			}
97374462Salfred		}
97474462Salfred	}
97574462Salfred	if (entry != -1) {
97674462Salfred		/* use this empty slot */
97774462Salfred		j = entry;
97874462Salfred	} else {
97974462Salfred		(void) free_slot_by_index(j);
98074462Salfred	}
98174462Salfred	if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
98274462Salfred		return (-1);
98374462Salfred	}
98474462Salfred	rpcb_rmtcalls++;	/* no of pending calls */
98574462Salfred	FINFO[j].flag = FINFO_ACTIVE;
98674462Salfred	FINFO[j].reply_type = reply_type;
98774462Salfred	FINFO[j].versnum = versnum;
98874462Salfred	FINFO[j].time = time_now;
98974462Salfred	FINFO[j].caller_xid = caller_xid;
99074462Salfred	FINFO[j].forward_fd = forward_fd;
99174462Salfred	/*
99274462Salfred	 * Though uaddr is not allocated here, it will still be freed
99374462Salfred	 * from free_slot_*().
99474462Salfred	 */
99574462Salfred	FINFO[j].uaddr = uaddr;
99674462Salfred	lastxid = lastxid + NFORWARD;
99778681Siedowse	/* Don't allow a zero xid below. */
99878681Siedowse	if ((u_int32_t)(lastxid + NFORWARD) <= NFORWARD)
99978681Siedowse		lastxid = NFORWARD;
100074462Salfred	FINFO[j].forward_xid = lastxid + j;	/* encode slot */
100178681Siedowse	*callxidp = FINFO[j].forward_xid;	/* forward on this xid */
100278681Siedowse	return (1);
100374462Salfred}
100474462Salfred
100574462Salfredstatic struct finfo *
100674462Salfredforward_find(u_int32_t reply_xid)
100774462Salfred{
100874462Salfred	int		i;
100974462Salfred
101078681Siedowse	i = reply_xid % (u_int32_t)NFORWARD;
101174462Salfred	if ((FINFO[i].flag & FINFO_ACTIVE) &&
101274462Salfred	    (FINFO[i].forward_xid == reply_xid)) {
101374462Salfred		return (&FINFO[i]);
101474462Salfred	}
101574462Salfred	return (NULL);
101674462Salfred}
101774462Salfred
101874462Salfredstatic int
101974462Salfredfree_slot_by_xid(u_int32_t xid)
102074462Salfred{
102174462Salfred	int entry;
102274462Salfred
102378681Siedowse	entry = xid % (u_int32_t)NFORWARD;
102474462Salfred	return (free_slot_by_index(entry));
102574462Salfred}
102674462Salfred
102774462Salfredstatic int
102874462Salfredfree_slot_by_index(int index)
102974462Salfred{
103074462Salfred	struct finfo	*fi;
103174462Salfred
103274462Salfred	fi = &FINFO[index];
103374462Salfred	if (fi->flag & FINFO_ACTIVE) {
103474462Salfred		netbuffree(fi->caller_addr);
103574462Salfred		/* XXX may be too big, but can't access xprt array here */
103674462Salfred		if (fi->forward_fd >= svc_maxfd)
103774462Salfred			svc_maxfd--;
103879723Siedowse		free(fi->uaddr);
103974462Salfred		fi->flag &= ~FINFO_ACTIVE;
104074462Salfred		rpcb_rmtcalls--;
104174462Salfred		return (1);
104274462Salfred	}
104374462Salfred	return (0);
104474462Salfred}
104574462Salfred
104674462Salfredstatic int
104774462Salfrednetbufcmp(struct netbuf *n1, struct netbuf *n2)
104874462Salfred{
104974462Salfred	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
105074462Salfred}
105174462Salfred
1052288384Sdelphijstatic bool_t
1053288384Sdelphijnetbuf_copybuf(struct netbuf *dst, const struct netbuf *src)
1054288384Sdelphij{
1055288384Sdelphij
1056288511Sdelphij	if (dst->len != src->len || dst->buf == NULL) {
1057288511Sdelphij		if (dst->buf != NULL)
1058288511Sdelphij			free(dst->buf);
1059288511Sdelphij		if ((dst->buf = malloc(src->len)) == NULL)
1060288511Sdelphij			return (FALSE);
1061288384Sdelphij
1062288511Sdelphij		dst->maxlen = dst->len = src->len;
1063288511Sdelphij	}
1064288384Sdelphij
1065288384Sdelphij	memcpy(dst->buf, src->buf, src->len);
1066288384Sdelphij	return (TRUE);
1067288384Sdelphij}
1068288384Sdelphij
106974462Salfredstatic struct netbuf *
107074462Salfrednetbufdup(struct netbuf *ap)
107174462Salfred{
107274462Salfred	struct netbuf  *np;
107374462Salfred
1074288384Sdelphij	if ((np = calloc(1, sizeof(struct netbuf))) == NULL)
107579723Siedowse		return (NULL);
1076288384Sdelphij	if (netbuf_copybuf(np, ap) == FALSE) {
107779723Siedowse		free(np);
107879723Siedowse		return (NULL);
107974462Salfred	}
108074462Salfred	return (np);
108174462Salfred}
108274462Salfred
108374462Salfredstatic void
108474462Salfrednetbuffree(struct netbuf *ap)
108574462Salfred{
108679806Sbrian	free(ap->buf);
1087288384Sdelphij	ap->buf = NULL;
108879723Siedowse	free(ap);
108974462Salfred}
109074462Salfred
109174462Salfred
109274462Salfred#define	MASKVAL	(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
1093109363Smbrextern bool_t __svc_clean_idle(fd_set *, int, bool_t);
109474462Salfred
109574462Salfredvoid
1096224001Sdelphijmy_svc_run(void)
109774462Salfred{
109874462Salfred	size_t nfds;
109974462Salfred	struct pollfd pollfds[FD_SETSIZE];
110074462Salfred	int poll_ret, check_ret;
110174462Salfred	int n;
110274462Salfred#ifdef SVC_RUN_DEBUG
110374462Salfred	int i;
110474462Salfred#endif
110574462Salfred	register struct pollfd	*p;
1106109363Smbr	fd_set cleanfds;
110774462Salfred
110874462Salfred	for (;;) {
110974462Salfred		p = pollfds;
111074462Salfred		for (n = 0; n <= svc_maxfd; n++) {
111174462Salfred			if (FD_ISSET(n, &svc_fdset)) {
111274462Salfred				p->fd = n;
111374462Salfred				p->events = MASKVAL;
111474462Salfred				p++;
111574462Salfred			}
111674462Salfred		}
111774462Salfred		nfds = p - pollfds;
111874462Salfred		poll_ret = 0;
111974462Salfred#ifdef SVC_RUN_DEBUG
112074462Salfred		if (debugging) {
112174462Salfred			fprintf(stderr, "polling for read on fd < ");
112274462Salfred			for (i = 0, p = pollfds; i < nfds; i++, p++)
112374462Salfred				if (p->events)
112474462Salfred					fprintf(stderr, "%d ", p->fd);
112574462Salfred			fprintf(stderr, ">\n");
112674462Salfred		}
112774462Salfred#endif
1128109363Smbr		switch (poll_ret = poll(pollfds, nfds, 30 * 1000)) {
112974462Salfred		case -1:
113074462Salfred			/*
113174462Salfred			 * We ignore all errors, continuing with the assumption
113274462Salfred			 * that it was set by the signal handlers (or any
113374462Salfred			 * other outside event) and not caused by poll().
113474462Salfred			 */
113574462Salfred		case 0:
1136109363Smbr			cleanfds = svc_fdset;
1137109363Smbr			__svc_clean_idle(&cleanfds, 30, FALSE);
113874462Salfred			continue;
113974462Salfred		default:
114074462Salfred#ifdef SVC_RUN_DEBUG
114174462Salfred			if (debugging) {
114274462Salfred				fprintf(stderr, "poll returned read fds < ");
114374462Salfred				for (i = 0, p = pollfds; i < nfds; i++, p++)
114474462Salfred					if (p->revents)
114574462Salfred						fprintf(stderr, "%d ", p->fd);
114674462Salfred				fprintf(stderr, ">\n");
114774462Salfred			}
114874462Salfred#endif
114974462Salfred			/*
115074462Salfred			 * If we found as many replies on callback fds
115174462Salfred			 * as the number of descriptors selectable which
115274462Salfred			 * poll() returned, there can be no more so we
115374462Salfred			 * don't call svc_getreq_poll.  Otherwise, there
115474462Salfred			 * must be another so we must call svc_getreq_poll.
115574462Salfred			 */
115674462Salfred			if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
115774462Salfred			    poll_ret)
115874462Salfred				continue;
115974462Salfred			svc_getreq_poll(pollfds, poll_ret-check_ret);
116074462Salfred		}
116174462Salfred#ifdef SVC_RUN_DEBUG
116274462Salfred		if (debugging) {
116374462Salfred			fprintf(stderr, "svc_maxfd now %u\n", svc_maxfd);
116474462Salfred		}
116574462Salfred#endif
116674462Salfred	}
116774462Salfred}
116874462Salfred
116974462Salfredstatic int
117074462Salfredcheck_rmtcalls(struct pollfd *pfds, int nfds)
117174462Salfred{
117274462Salfred	int j, ncallbacks_found = 0, rmtcalls_pending;
117374462Salfred	SVCXPRT *xprt;
117474462Salfred
117574462Salfred	if (rpcb_rmtcalls == 0)
117674462Salfred		return (0);
117774462Salfred
117874462Salfred	rmtcalls_pending = rpcb_rmtcalls;
117974462Salfred	for (j = 0; j < nfds; j++) {
118074462Salfred		if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
118174462Salfred			if (pfds[j].revents) {
118274462Salfred				ncallbacks_found++;
118374462Salfred#ifdef DEBUG_RMTCALL
118474462Salfred			if (debugging)
118574462Salfred				fprintf(stderr,
118674462Salfred"my_svc_run:  polled on forwarding fd %d, netid %s - calling handle_reply\n",
118774462Salfred		pfds[j].fd, xprt->xp_netid);
118874462Salfred#endif
118974462Salfred				handle_reply(pfds[j].fd, xprt);
119074462Salfred				pfds[j].revents = 0;
119174462Salfred				if (ncallbacks_found >= rmtcalls_pending) {
119274462Salfred					break;
119374462Salfred				}
119474462Salfred			}
119574462Salfred		}
119674462Salfred	}
119774462Salfred	return (ncallbacks_found);
119874462Salfred}
119974462Salfred
120074462Salfredstatic void
120174462Salfredxprt_set_caller(SVCXPRT *xprt, struct finfo *fi)
120274462Salfred{
120374462Salfred	u_int32_t *xidp;
120474462Salfred
1205288384Sdelphij	netbuf_copybuf(svc_getrpccaller(xprt), fi->caller_addr);
120674462Salfred	xidp = __rpcb_get_dg_xidp(xprt);
120774462Salfred	*xidp = fi->caller_xid;
120874462Salfred}
120974462Salfred
121074462Salfred/*
121174462Salfred * Call svcerr_systemerr() only if RPCBVERS4
121274462Salfred */
121374462Salfredstatic void
121474462Salfredsend_svcsyserr(SVCXPRT *xprt, struct finfo *fi)
121574462Salfred{
121674462Salfred	if (fi->reply_type == RPCBPROC_INDIRECT) {
121774462Salfred		xprt_set_caller(xprt, fi);
121874462Salfred		svcerr_systemerr(xprt);
121974462Salfred	}
122074462Salfred	return;
122174462Salfred}
122274462Salfred
122374462Salfredstatic void
122474462Salfredhandle_reply(int fd, SVCXPRT *xprt)
122574462Salfred{
122674462Salfred	XDR		reply_xdrs;
122774462Salfred	struct rpc_msg	reply_msg;
122874462Salfred	struct rpc_err	reply_error;
122974462Salfred	char		*buffer;
123074462Salfred	struct finfo	*fi;
123174462Salfred	int		inlen, pos, len;
123274462Salfred	struct r_rmtcall_args a;
123374462Salfred	struct sockaddr_storage ss;
123474462Salfred	socklen_t fromlen;
123574462Salfred#ifdef SVC_RUN_DEBUG
123674462Salfred	char *uaddr;
123774462Salfred#endif
123874462Salfred
123974462Salfred	buffer = malloc(RPC_BUF_MAX);
124074462Salfred	if (buffer == NULL)
124174462Salfred		goto done;
124274462Salfred
124374462Salfred	do {
1244203604Simp		fromlen = sizeof(ss);
124574462Salfred		inlen = recvfrom(fd, buffer, RPC_BUF_MAX, 0,
124674462Salfred			    (struct sockaddr *)&ss, &fromlen);
124774462Salfred	} while (inlen < 0 && errno == EINTR);
124874462Salfred	if (inlen < 0) {
124974462Salfred		if (debugging)
125074462Salfred			fprintf(stderr,
125174462Salfred	"handle_reply:  recvfrom returned %d, errno %d\n", inlen, errno);
125274462Salfred		goto done;
125374462Salfred	}
125474462Salfred
125574462Salfred	reply_msg.acpted_rply.ar_verf = _null_auth;
125674462Salfred	reply_msg.acpted_rply.ar_results.where = 0;
125774462Salfred	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
125874462Salfred
125974462Salfred	xdrmem_create(&reply_xdrs, buffer, (u_int)inlen, XDR_DECODE);
126074462Salfred	if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
126174462Salfred		if (debugging)
126274462Salfred			(void) fprintf(stderr,
126374462Salfred				"handle_reply:  xdr_replymsg failed\n");
126474462Salfred		goto done;
126574462Salfred	}
126674462Salfred	fi = forward_find(reply_msg.rm_xid);
126774462Salfred#ifdef	SVC_RUN_DEBUG
126874462Salfred	if (debugging) {
126974462Salfred		fprintf(stderr, "handle_reply:  reply xid: %d fi addr: %p\n",
127074462Salfred			reply_msg.rm_xid, fi);
127174462Salfred	}
127274462Salfred#endif
127374462Salfred	if (fi == NULL) {
127474462Salfred		goto done;
127574462Salfred	}
127674462Salfred	_seterr_reply(&reply_msg, &reply_error);
127774462Salfred	if (reply_error.re_status != RPC_SUCCESS) {
127874462Salfred		if (debugging)
127974462Salfred			(void) fprintf(stderr, "handle_reply:  %s\n",
128074462Salfred				clnt_sperrno(reply_error.re_status));
128174462Salfred		send_svcsyserr(xprt, fi);
128274462Salfred		goto done;
128374462Salfred	}
128474462Salfred	pos = XDR_GETPOS(&reply_xdrs);
128574462Salfred	len = inlen - pos;
128674462Salfred	a.rmt_args.args = &buffer[pos];
128774462Salfred	a.rmt_args.arglen = len;
128874462Salfred	a.rmt_uaddr = fi->uaddr;
128974462Salfred	a.rmt_localvers = fi->versnum;
129074462Salfred
129174462Salfred	xprt_set_caller(xprt, fi);
129274462Salfred#ifdef	SVC_RUN_DEBUG
129374462Salfred	uaddr =	taddr2uaddr(rpcbind_get_conf("udp"),
129474462Salfred				    svc_getrpccaller(xprt));
129574462Salfred	if (debugging) {
129674462Salfred		fprintf(stderr, "handle_reply:  forwarding address %s to %s\n",
129774462Salfred			a.rmt_uaddr, uaddr ? uaddr : "unknown");
129874462Salfred	}
129974462Salfred	if (uaddr)
130079723Siedowse		free(uaddr);
130174462Salfred#endif
130274462Salfred	svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (char *) &a);
130374462Salfreddone:
130474462Salfred	if (buffer)
130574462Salfred		free(buffer);
130674462Salfred
130774462Salfred	if (reply_msg.rm_xid == 0) {
130874462Salfred#ifdef	SVC_RUN_DEBUG
130974462Salfred	if (debugging) {
131074462Salfred		fprintf(stderr, "handle_reply:  NULL xid on exit!\n");
131174462Salfred	}
131274462Salfred#endif
131374462Salfred	} else
131474462Salfred		(void) free_slot_by_xid(reply_msg.rm_xid);
131574462Salfred	return;
131674462Salfred}
131774462Salfred
131874462Salfredstatic void
131974462Salfredfind_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
132074462Salfred{
132174462Salfred	register rpcblist_ptr rbl;
1322104592Salfred	unsigned int lowv = 0;
1323104592Salfred	unsigned int highv = 0;
132474462Salfred
132574462Salfred	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
132674462Salfred		if ((rbl->rpcb_map.r_prog != prog) ||
132774462Salfred		    ((rbl->rpcb_map.r_netid != NULL) &&
132874462Salfred			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
132974462Salfred			continue;
133074462Salfred		if (lowv == 0) {
133174462Salfred			highv = rbl->rpcb_map.r_vers;
133274462Salfred			lowv = highv;
133374462Salfred		} else if (rbl->rpcb_map.r_vers < lowv) {
133474462Salfred			lowv = rbl->rpcb_map.r_vers;
133574462Salfred		} else if (rbl->rpcb_map.r_vers > highv) {
133674462Salfred			highv = rbl->rpcb_map.r_vers;
133774462Salfred		}
133874462Salfred	}
133974462Salfred	*lowvp = lowv;
134074462Salfred	*highvp = highv;
134174462Salfred	return;
134274462Salfred}
134374462Salfred
134474462Salfred/*
134574462Salfred * returns the item with the given program, version number and netid.
134674462Salfred * If that version number is not found, it returns the item with that
134774462Salfred * program number, so that address is now returned to the caller. The
134874462Salfred * caller when makes a call to this program, version number, the call
134974462Salfred * will fail and it will return with PROGVERS_MISMATCH. The user can
135074462Salfred * then determine the highest and the lowest version number for this
135174462Salfred * program using clnt_geterr() and use those program version numbers.
135274462Salfred *
135374462Salfred * Returns the RPCBLIST for the given prog, vers and netid
135474462Salfred */
135574462Salfredstatic rpcblist_ptr
135674462Salfredfind_service(rpcprog_t prog, rpcvers_t vers, char *netid)
135774462Salfred{
135874462Salfred	register rpcblist_ptr hit = NULL;
135974462Salfred	register rpcblist_ptr rbl;
136074462Salfred
136174462Salfred	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
136274462Salfred		if ((rbl->rpcb_map.r_prog != prog) ||
136374462Salfred		    ((rbl->rpcb_map.r_netid != NULL) &&
136474462Salfred			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
136574462Salfred			continue;
136674462Salfred		hit = rbl;
136774462Salfred		if (rbl->rpcb_map.r_vers == vers)
136874462Salfred			break;
136974462Salfred	}
137074462Salfred	return (hit);
137174462Salfred}
137274462Salfred
137374462Salfred/*
137474462Salfred * Copies the name associated with the uid of the caller and returns
137574462Salfred * a pointer to it.  Similar to getwd().
137674462Salfred */
137774462Salfredstatic char *
137874462Salfredgetowner(SVCXPRT *transp, char *owner, size_t ownersize)
137974462Salfred{
138074627Salfred	uid_t uid;
138174627Salfred
138274627Salfred	if (__rpc_get_local_uid(transp, &uid) < 0)
138374627Salfred                strlcpy(owner, "unknown", ownersize);
138474627Salfred	else if (uid == 0)
138574462Salfred		strlcpy(owner, "superuser", ownersize);
138674462Salfred	else
138774627Salfred		snprintf(owner, ownersize, "%d", uid);
138874462Salfred
138974462Salfred	return owner;
139074462Salfred}
139174462Salfred
139274462Salfred#ifdef PORTMAP
139374462Salfred/*
139474462Salfred * Add this to the pmap list only if it is UDP or TCP.
139574462Salfred */
139674462Salfredstatic int
139774462Salfredadd_pmaplist(RPCB *arg)
139874462Salfred{
139974462Salfred	struct pmap pmap;
140074462Salfred	struct pmaplist *pml;
140174462Salfred	int h1, h2, h3, h4, p1, p2;
140274462Salfred
140374462Salfred	if (strcmp(arg->r_netid, udptrans) == 0) {
140474462Salfred		/* It is UDP! */
140574462Salfred		pmap.pm_prot = IPPROTO_UDP;
140674462Salfred	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
140774462Salfred		/* It is TCP */
140874462Salfred		pmap.pm_prot = IPPROTO_TCP;
140974462Salfred	} else
1410108533Sschweikh		/* Not an IP protocol */
141174462Salfred		return (0);
141274462Salfred
141374462Salfred	/* interpret the universal address for TCP/IP */
141474462Salfred	if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
141574462Salfred		&h1, &h2, &h3, &h4, &p1, &p2) != 6)
141674462Salfred		return (0);
141774462Salfred	pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
141874462Salfred	pmap.pm_prog = arg->r_prog;
141974462Salfred	pmap.pm_vers = arg->r_vers;
142074462Salfred	/*
142174462Salfred	 * add to END of list
142274462Salfred	 */
142396788Sjmallett	pml = malloc(sizeof (struct pmaplist));
142474462Salfred	if (pml == NULL) {
142574462Salfred		(void) syslog(LOG_ERR, "rpcbind: no memory!\n");
142674462Salfred		return (1);
142774462Salfred	}
142874462Salfred	pml->pml_map = pmap;
142974462Salfred	pml->pml_next = NULL;
143074462Salfred	if (list_pml == NULL) {
143174462Salfred		list_pml = pml;
143274462Salfred	} else {
143374462Salfred		struct pmaplist *fnd;
143474462Salfred
143574462Salfred		/* Attach to the end of the list */
143674462Salfred		for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
143774462Salfred			;
143874462Salfred		fnd->pml_next = pml;
143974462Salfred	}
144074462Salfred	return (0);
144174462Salfred}
144274462Salfred
144374462Salfred/*
144474462Salfred * Delete this from the pmap list only if it is UDP or TCP.
144574462Salfred */
144674462Salfredstatic int
144774462Salfreddel_pmaplist(RPCB *arg)
144874462Salfred{
144974462Salfred	struct pmaplist *pml;
145074462Salfred	struct pmaplist *prevpml, *fnd;
1451104592Salfred	unsigned long prot;
145274462Salfred
145374462Salfred	if (strcmp(arg->r_netid, udptrans) == 0) {
145474462Salfred		/* It is UDP! */
145574462Salfred		prot = IPPROTO_UDP;
145674462Salfred	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
145774462Salfred		/* It is TCP */
145874462Salfred		prot = IPPROTO_TCP;
1459121656Smbr	} else if (arg->r_netid[0] == 0) {
146074462Salfred		prot = 0;	/* Remove all occurrences */
146174462Salfred	} else {
1462108533Sschweikh		/* Not an IP protocol */
146374462Salfred		return (0);
146474462Salfred	}
146574462Salfred	for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
146674462Salfred		if ((pml->pml_map.pm_prog != arg->r_prog) ||
146774462Salfred			(pml->pml_map.pm_vers != arg->r_vers) ||
146874462Salfred			(prot && (pml->pml_map.pm_prot != prot))) {
146974462Salfred			/* both pml & prevpml move forwards */
147074462Salfred			prevpml = pml;
147174462Salfred			pml = pml->pml_next;
147274462Salfred			continue;
147374462Salfred		}
147474462Salfred		/* found it; pml moves forward, prevpml stays */
147574462Salfred		fnd = pml;
147674462Salfred		pml = pml->pml_next;
147774462Salfred		if (prevpml == NULL)
147874462Salfred			list_pml = pml;
147974462Salfred		else
148074462Salfred			prevpml->pml_next = pml;
148179723Siedowse		free(fnd);
148274462Salfred	}
148374462Salfred	return (0);
148474462Salfred}
148574462Salfred#endif /* PORTMAP */
1486