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