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