xref: /titanic_52/usr/src/cmd/rpcbind/check_bound.c (revision 8f6d9dae92449b59bdafcb7777bc32f1b2726e48)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
25*8f6d9daeSMarcel Telka /*
26*8f6d9daeSMarcel Telka  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
27*8f6d9daeSMarcel Telka  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
307c478bd9Sstevel@tonic-gate /* All Rights Reserved */
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
337c478bd9Sstevel@tonic-gate  * The Regents of the University of California
347c478bd9Sstevel@tonic-gate  * All Rights Reserved
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
377c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
387c478bd9Sstevel@tonic-gate  * contributors.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * check_bound.c
437c478bd9Sstevel@tonic-gate  * Checks to see whether the program is still bound to the
447c478bd9Sstevel@tonic-gate  * claimed address and returns the univeral merged address
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include <stdio.h>
497c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
507c478bd9Sstevel@tonic-gate #include <netconfig.h>
517c478bd9Sstevel@tonic-gate #include <netdir.h>
527c478bd9Sstevel@tonic-gate #include <sys/syslog.h>
537c478bd9Sstevel@tonic-gate #include <stdlib.h>
547c478bd9Sstevel@tonic-gate #include "rpcbind.h"
557c478bd9Sstevel@tonic-gate #include <string.h>
567c478bd9Sstevel@tonic-gate /* the following just to get my address */
577c478bd9Sstevel@tonic-gate #include <errno.h>
587c478bd9Sstevel@tonic-gate #include <sys/socket.h>
597c478bd9Sstevel@tonic-gate #include <netinet/in.h>
60*8f6d9daeSMarcel Telka #include <thread.h>
61*8f6d9daeSMarcel Telka #include <synch.h>
62*8f6d9daeSMarcel Telka #include <syslog.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate struct fdlist {
657c478bd9Sstevel@tonic-gate 	int fd;
66*8f6d9daeSMarcel Telka 	mutex_t fd_lock;	/* protects fd */
677c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
687c478bd9Sstevel@tonic-gate 	struct fdlist *next;
697c478bd9Sstevel@tonic-gate 	int check_binding;
707c478bd9Sstevel@tonic-gate };
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static struct fdlist *fdhead;	/* Link list of the check fd's */
737c478bd9Sstevel@tonic-gate static struct fdlist *fdtail;
747c478bd9Sstevel@tonic-gate static char *nullstring = "";
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Returns 1 if the given address is bound for the given addr & transport
787c478bd9Sstevel@tonic-gate  * For all error cases, we assume that the address is bound
797c478bd9Sstevel@tonic-gate  * Returns 0 for success.
80*8f6d9daeSMarcel Telka  *
81*8f6d9daeSMarcel Telka  * fdl: My FD list
82*8f6d9daeSMarcel Telka  * uaddr: the universal address
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate static bool_t
85*8f6d9daeSMarcel Telka check_bound(struct fdlist *fdl, char *uaddr)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	int fd;
887c478bd9Sstevel@tonic-gate 	struct netbuf *na;
897c478bd9Sstevel@tonic-gate 	struct t_bind taddr, *baddr;
907c478bd9Sstevel@tonic-gate 	int ans;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	if (fdl->check_binding == FALSE)
937c478bd9Sstevel@tonic-gate 		return (TRUE);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	na = uaddr2taddr(fdl->nconf, uaddr);
967c478bd9Sstevel@tonic-gate 	if (!na)
977c478bd9Sstevel@tonic-gate 		return (TRUE); /* punt, should never happen */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	taddr.addr = *na;
1007c478bd9Sstevel@tonic-gate 	taddr.qlen = 1;
101*8f6d9daeSMarcel Telka 	(void) mutex_lock(&fdl->fd_lock);
102*8f6d9daeSMarcel Telka 	fd = fdl->fd;
1037c478bd9Sstevel@tonic-gate 	baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
1047c478bd9Sstevel@tonic-gate 	if (baddr == NULL) {
105*8f6d9daeSMarcel Telka 		(void) mutex_unlock(&fdl->fd_lock);
1067c478bd9Sstevel@tonic-gate 		netdir_free((char *)na, ND_ADDR);
1077c478bd9Sstevel@tonic-gate 		return (TRUE);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 	if (t_bind(fd, &taddr, baddr) != 0) {
110*8f6d9daeSMarcel Telka 		(void) mutex_unlock(&fdl->fd_lock);
1117c478bd9Sstevel@tonic-gate 		netdir_free((char *)na, ND_ADDR);
1127c478bd9Sstevel@tonic-gate 		(void) t_free((char *)baddr, T_BIND);
1137c478bd9Sstevel@tonic-gate 		return (TRUE);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 	if (t_unbind(fd) != 0) {
1167c478bd9Sstevel@tonic-gate 		/* Bad fd. Purge this fd */
1177c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
1187c478bd9Sstevel@tonic-gate 		fdl->fd = t_open(fdl->nconf->nc_device, O_RDWR, NULL);
1197c478bd9Sstevel@tonic-gate 		if (fdl->fd == -1)
1207c478bd9Sstevel@tonic-gate 			fdl->check_binding = FALSE;
1217c478bd9Sstevel@tonic-gate 	}
122*8f6d9daeSMarcel Telka 	(void) mutex_unlock(&fdl->fd_lock);
123*8f6d9daeSMarcel Telka 	ans = memcmp(taddr.addr.buf, baddr->addr.buf, baddr->addr.len);
124*8f6d9daeSMarcel Telka 	netdir_free((char *)na, ND_ADDR);
125*8f6d9daeSMarcel Telka 	(void) t_free((char *)baddr, T_BIND);
1267c478bd9Sstevel@tonic-gate 	return (ans == 0 ? FALSE : TRUE);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * Keep open one more file descriptor for this transport, which
1317c478bd9Sstevel@tonic-gate  * will be used to determine whether the given service is up
1327c478bd9Sstevel@tonic-gate  * or not by trying to bind to the registered address.
1337c478bd9Sstevel@tonic-gate  * We are ignoring errors here. It trashes taddr and baddr;
1347c478bd9Sstevel@tonic-gate  * but that perhaps should not matter.
1357c478bd9Sstevel@tonic-gate  *
1367c478bd9Sstevel@tonic-gate  * We check for the following conditions:
1377c478bd9Sstevel@tonic-gate  *	1. Is it possible for t_bind to fail in the case where
1387c478bd9Sstevel@tonic-gate  *		we bind to an already bound address and have any
1397c478bd9Sstevel@tonic-gate  *		other error number besides TNOADDR.
140*8f6d9daeSMarcel Telka  *	2. If an address is specified in bind addr, can I bind to
1417c478bd9Sstevel@tonic-gate  *		the same address.
1427c478bd9Sstevel@tonic-gate  *	3. If NULL is specified in bind addr, can I bind to the
1437c478bd9Sstevel@tonic-gate  *		address to which the fd finally got bound.
1447c478bd9Sstevel@tonic-gate  */
1457c478bd9Sstevel@tonic-gate int
146*8f6d9daeSMarcel Telka add_bndlist(struct netconfig *nconf, struct t_bind *taddr, struct t_bind *baddr)
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	int fd;
1497c478bd9Sstevel@tonic-gate 	struct fdlist *fdl;
1507c478bd9Sstevel@tonic-gate 	struct netconfig *newnconf;
1517c478bd9Sstevel@tonic-gate 	struct t_info tinfo;
1527c478bd9Sstevel@tonic-gate 	struct t_bind tmpaddr;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	newnconf = getnetconfigent(nconf->nc_netid);
1557c478bd9Sstevel@tonic-gate 	if (newnconf == NULL)
1567c478bd9Sstevel@tonic-gate 		return (-1);
1577c478bd9Sstevel@tonic-gate 	fdl = (struct fdlist *)malloc((uint_t)sizeof (struct fdlist));
1587c478bd9Sstevel@tonic-gate 	if (fdl == NULL) {
1597c478bd9Sstevel@tonic-gate 		freenetconfigent(newnconf);
1607c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "no memory!");
1617c478bd9Sstevel@tonic-gate 		return (-1);
1627c478bd9Sstevel@tonic-gate 	}
163*8f6d9daeSMarcel Telka 	(void) mutex_init(&fdl->fd_lock, USYNC_THREAD, NULL);
1647c478bd9Sstevel@tonic-gate 	fdl->nconf = newnconf;
1657c478bd9Sstevel@tonic-gate 	fdl->next = NULL;
1667c478bd9Sstevel@tonic-gate 	if (fdhead == NULL) {
1677c478bd9Sstevel@tonic-gate 		fdhead = fdl;
1687c478bd9Sstevel@tonic-gate 		fdtail = fdl;
1697c478bd9Sstevel@tonic-gate 	} else {
1707c478bd9Sstevel@tonic-gate 		fdtail->next = fdl;
1717c478bd9Sstevel@tonic-gate 		fdtail = fdl;
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 	fdl->check_binding = FALSE;
1747c478bd9Sstevel@tonic-gate 	if ((fdl->fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) < 0) {
1757c478bd9Sstevel@tonic-gate 		/*
1767c478bd9Sstevel@tonic-gate 		 * Note that we haven't dequeued this entry nor have we freed
1777c478bd9Sstevel@tonic-gate 		 * the netconfig structure.
1787c478bd9Sstevel@tonic-gate 		 */
1797c478bd9Sstevel@tonic-gate 		if (debugging) {
1807c478bd9Sstevel@tonic-gate 			fprintf(stderr,
1817c478bd9Sstevel@tonic-gate 			    "%s: add_bndlist cannot open connection: %s",
1827c478bd9Sstevel@tonic-gate 			    nconf->nc_netid, t_errlist[t_errno]);
1837c478bd9Sstevel@tonic-gate 		}
1847c478bd9Sstevel@tonic-gate 		return (-1);
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/* Set the qlen only for cots transports */
1887c478bd9Sstevel@tonic-gate 	switch (tinfo.servtype) {
1897c478bd9Sstevel@tonic-gate 	case T_COTS:
1907c478bd9Sstevel@tonic-gate 	case T_COTS_ORD:
1917c478bd9Sstevel@tonic-gate 		taddr->qlen = 1;
1927c478bd9Sstevel@tonic-gate 		break;
1937c478bd9Sstevel@tonic-gate 	case T_CLTS:
1947c478bd9Sstevel@tonic-gate 		taddr->qlen = 0;
1957c478bd9Sstevel@tonic-gate 		break;
1967c478bd9Sstevel@tonic-gate 	default:
1977c478bd9Sstevel@tonic-gate 		goto error;
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	if (t_bind(fdl->fd, taddr, baddr) != 0) {
2017c478bd9Sstevel@tonic-gate 		if (t_errno == TNOADDR) {
2027c478bd9Sstevel@tonic-gate 			fdl->check_binding = TRUE;
2037c478bd9Sstevel@tonic-gate 			return (0);	/* All is fine */
2047c478bd9Sstevel@tonic-gate 		}
2057c478bd9Sstevel@tonic-gate 		/* Perhaps condition #1 */
2067c478bd9Sstevel@tonic-gate 		if (debugging) {
2077c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: add_bndlist cannot bind (1): %s",
2087c478bd9Sstevel@tonic-gate 			    nconf->nc_netid, t_errlist[t_errno]);
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 		goto not_bound;
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	/* Condition #2 */
2147c478bd9Sstevel@tonic-gate 	if (!memcmp(taddr->addr.buf, baddr->addr.buf,
2157c478bd9Sstevel@tonic-gate 	    (int)baddr->addr.len)) {
2167c478bd9Sstevel@tonic-gate 		goto not_bound;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/* Condition #3 */
2207c478bd9Sstevel@tonic-gate 	t_unbind(fdl->fd);
2217c478bd9Sstevel@tonic-gate 	/* Set the qlen only for cots transports */
2227c478bd9Sstevel@tonic-gate 	switch (tinfo.servtype) {
2237c478bd9Sstevel@tonic-gate 	case T_COTS:
2247c478bd9Sstevel@tonic-gate 	case T_COTS_ORD:
2257c478bd9Sstevel@tonic-gate 		tmpaddr.qlen = 1;
2267c478bd9Sstevel@tonic-gate 		break;
2277c478bd9Sstevel@tonic-gate 	case T_CLTS:
2287c478bd9Sstevel@tonic-gate 		tmpaddr.qlen = 0;
2297c478bd9Sstevel@tonic-gate 		break;
2307c478bd9Sstevel@tonic-gate 	default:
2317c478bd9Sstevel@tonic-gate 		goto error;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	tmpaddr.addr.len = tmpaddr.addr.maxlen = 0;
2347c478bd9Sstevel@tonic-gate 	tmpaddr.addr.buf = NULL;
2357c478bd9Sstevel@tonic-gate 	if (t_bind(fdl->fd, &tmpaddr, taddr) != 0) {
2367c478bd9Sstevel@tonic-gate 		if (debugging) {
2377c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: add_bndlist cannot bind (2): %s",
2387c478bd9Sstevel@tonic-gate 			    nconf->nc_netid, t_errlist[t_errno]);
2397c478bd9Sstevel@tonic-gate 		}
2407c478bd9Sstevel@tonic-gate 		goto error;
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	/* Now fdl->fd is bound to a transport chosen address */
2437c478bd9Sstevel@tonic-gate 	if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) < 0) {
2447c478bd9Sstevel@tonic-gate 		if (debugging) {
2457c478bd9Sstevel@tonic-gate 			fprintf(stderr,
2467c478bd9Sstevel@tonic-gate 			    "%s: add_bndlist cannot open connection: %s",
2477c478bd9Sstevel@tonic-gate 			    nconf->nc_netid, t_errlist[t_errno]);
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		goto error;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 	if (t_bind(fd, taddr, baddr) != 0) {
2527c478bd9Sstevel@tonic-gate 		if (t_errno == TNOADDR) {
2537c478bd9Sstevel@tonic-gate 			/*
2547c478bd9Sstevel@tonic-gate 			 * This transport is schizo.  Previously it handled a
2557c478bd9Sstevel@tonic-gate 			 * request to bind to an already bound transport by
2567c478bd9Sstevel@tonic-gate 			 * returning a different bind address, and now it's
2577c478bd9Sstevel@tonic-gate 			 * returning a TNOADDR for essentially the same
2587c478bd9Sstevel@tonic-gate 			 * request.  The spec may allow this behavior, so
2597c478bd9Sstevel@tonic-gate 			 * we'll just assume we can't do bind checking with
2607c478bd9Sstevel@tonic-gate 			 * this transport.
2617c478bd9Sstevel@tonic-gate 			 */
262*8f6d9daeSMarcel Telka 			t_close(fd);
2637c478bd9Sstevel@tonic-gate 			goto not_bound;
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 		if (debugging) {
2667c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s: add_bndlist cannot bind (3): %s",
2677c478bd9Sstevel@tonic-gate 			    nconf->nc_netid, t_errlist[t_errno]);
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 		t_close(fd);
2707c478bd9Sstevel@tonic-gate 		goto error;
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 	t_close(fd);
2737c478bd9Sstevel@tonic-gate 	if (!memcmp(taddr->addr.buf, baddr->addr.buf,
2747c478bd9Sstevel@tonic-gate 	    (int)baddr->addr.len)) {
2757c478bd9Sstevel@tonic-gate 		switch (tinfo.servtype) {
2767c478bd9Sstevel@tonic-gate 		case T_COTS:
2777c478bd9Sstevel@tonic-gate 		case T_COTS_ORD:
2787c478bd9Sstevel@tonic-gate 			if (baddr->qlen == 1) {
2797c478bd9Sstevel@tonic-gate 				goto not_bound;
2807c478bd9Sstevel@tonic-gate 			}
2817c478bd9Sstevel@tonic-gate 			break;
2827c478bd9Sstevel@tonic-gate 		case T_CLTS:
2837c478bd9Sstevel@tonic-gate 			goto not_bound;
2847c478bd9Sstevel@tonic-gate 		default:
2857c478bd9Sstevel@tonic-gate 			goto error;
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	t_unbind(fdl->fd);
2907c478bd9Sstevel@tonic-gate 	fdl->check_binding = TRUE;
2917c478bd9Sstevel@tonic-gate 	return (0);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate not_bound:
2947c478bd9Sstevel@tonic-gate 	t_close(fdl->fd);
2957c478bd9Sstevel@tonic-gate 	fdl->fd = -1;
2967c478bd9Sstevel@tonic-gate 	return (1);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate error:
2997c478bd9Sstevel@tonic-gate 	t_close(fdl->fd);
3007c478bd9Sstevel@tonic-gate 	fdl->fd = -1;
3017c478bd9Sstevel@tonic-gate 	return (-1);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate bool_t
305*8f6d9daeSMarcel Telka is_bound(char *netid, char *uaddr)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	struct fdlist *fdl;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	for (fdl = fdhead; fdl; fdl = fdl->next)
3107c478bd9Sstevel@tonic-gate 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
3117c478bd9Sstevel@tonic-gate 			break;
3127c478bd9Sstevel@tonic-gate 	if (fdl == NULL)
3137c478bd9Sstevel@tonic-gate 		return (TRUE);
3147c478bd9Sstevel@tonic-gate 	return (check_bound(fdl, uaddr));
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /* Return pointer to port string in the universal address */
3187c478bd9Sstevel@tonic-gate #define	UADDR_PRT_INDX(UADDR, PORT) { \
3197c478bd9Sstevel@tonic-gate 	PORT = strrchr(UADDR, '.'); \
3207c478bd9Sstevel@tonic-gate 	while (*--PORT != '.'); }
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * Returns NULL if there was some system error.
3237c478bd9Sstevel@tonic-gate  * Returns "" if the address was not bound, i.e the server crashed.
3247c478bd9Sstevel@tonic-gate  * Returns the merged address otherwise.
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate char *
327*8f6d9daeSMarcel Telka mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	struct fdlist *fdl;
3307c478bd9Sstevel@tonic-gate 	struct nd_mergearg ma;
3317c478bd9Sstevel@tonic-gate 	int stat;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	for (fdl = fdhead; fdl; fdl = fdl->next)
3347c478bd9Sstevel@tonic-gate 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
3357c478bd9Sstevel@tonic-gate 			break;
3367c478bd9Sstevel@tonic-gate 	if (fdl == NULL)
3377c478bd9Sstevel@tonic-gate 		return (NULL);
3387c478bd9Sstevel@tonic-gate 	if (check_bound(fdl, uaddr) == FALSE)
3397c478bd9Sstevel@tonic-gate 		/* that server died */
3407c478bd9Sstevel@tonic-gate 		return (nullstring);
3417c478bd9Sstevel@tonic-gate 	/*
3427c478bd9Sstevel@tonic-gate 	 * If saddr is not NULL, the remote client may have included the
3437c478bd9Sstevel@tonic-gate 	 * address by which it contacted us.  Use that for the "client" uaddr,
3447c478bd9Sstevel@tonic-gate 	 * otherwise use the info from the SVCXPRT.
3457c478bd9Sstevel@tonic-gate 	 */
3467c478bd9Sstevel@tonic-gate 	if (saddr != NULL) {
3477c478bd9Sstevel@tonic-gate 		ma.c_uaddr = saddr;
3487c478bd9Sstevel@tonic-gate 	} else {
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		/* retrieve the client's address */
3517c478bd9Sstevel@tonic-gate 		ma.c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
3527c478bd9Sstevel@tonic-gate 		if (ma.c_uaddr == NULL) {
3537c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "taddr2uaddr failed for %s: %s",
3547c478bd9Sstevel@tonic-gate 			    fdl->nconf->nc_netid, netdir_sperror());
3557c478bd9Sstevel@tonic-gate 			return (NULL);
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
360*8f6d9daeSMarcel Telka 	/* Not an INET address? */
3617c478bd9Sstevel@tonic-gate 	if ((strcmp(fdl->nconf->nc_protofmly, NC_INET) != 0) &&
3627c478bd9Sstevel@tonic-gate 	    (strcmp(fdl->nconf->nc_protofmly, NC_INET6) != 0)) {
3637c478bd9Sstevel@tonic-gate 		ma.s_uaddr = uaddr;
3647c478bd9Sstevel@tonic-gate 		stat = netdir_options(fdl->nconf, ND_MERGEADDR, 0, (char *)&ma);
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 	/* Inet address, but no xp_ltaddr */
3677c478bd9Sstevel@tonic-gate 	else if ((ma.s_uaddr = taddr2uaddr(fdl->nconf,
3687c478bd9Sstevel@tonic-gate 	    &(xprt)->xp_ltaddr)) == NULL) {
3697c478bd9Sstevel@tonic-gate 		ma.s_uaddr = uaddr;
3707c478bd9Sstevel@tonic-gate 		stat = netdir_options(fdl->nconf, ND_MERGEADDR, 0, (char *)&ma);
3717c478bd9Sstevel@tonic-gate 	} else {
3727c478bd9Sstevel@tonic-gate 		/*
3737c478bd9Sstevel@tonic-gate 		 * (xprt)->xp_ltaddr contains portmap's port address.
3747c478bd9Sstevel@tonic-gate 		 * Overwrite this with actual application's port address
3757c478bd9Sstevel@tonic-gate 		 * before returning to the caller.
3767c478bd9Sstevel@tonic-gate 		 */
3777c478bd9Sstevel@tonic-gate 		char *s_uport, *uport;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		/* Get the INET/INET6 address part from ma.s_uaddr */
3807c478bd9Sstevel@tonic-gate 		UADDR_PRT_INDX(ma.s_uaddr, s_uport);
3817c478bd9Sstevel@tonic-gate 		*s_uport = '\0';
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 		/* Get the port info from uaddr */
3847c478bd9Sstevel@tonic-gate 		UADDR_PRT_INDX(uaddr, uport);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		ma.m_uaddr = malloc(strlen(ma.s_uaddr) + strlen(uport) + 1);
3877c478bd9Sstevel@tonic-gate 		if (ma.m_uaddr == NULL) {
3887c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "mergeaddr: no memory!");
3897c478bd9Sstevel@tonic-gate 			free(ma.s_uaddr);
3907c478bd9Sstevel@tonic-gate 			if (saddr == NULL)
3917c478bd9Sstevel@tonic-gate 				free(ma.c_uaddr);
3927c478bd9Sstevel@tonic-gate 			return (NULL);
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		/* Copy IP address into the Universal address holder */
3967c478bd9Sstevel@tonic-gate 		strcpy(ma.m_uaddr, ma.s_uaddr);
3977c478bd9Sstevel@tonic-gate 		/* Append port info to the Universal address holder */
3987c478bd9Sstevel@tonic-gate 		strcat(ma.m_uaddr, uport);
3997c478bd9Sstevel@tonic-gate 		free(ma.s_uaddr);
4007c478bd9Sstevel@tonic-gate 		stat = 0;
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 	if (saddr == NULL) {
4037c478bd9Sstevel@tonic-gate 		free(ma.c_uaddr);
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 	if (stat) {
4067c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "netdir_merge failed for %s: %s",
4077c478bd9Sstevel@tonic-gate 		    fdl->nconf->nc_netid, netdir_sperror());
4087c478bd9Sstevel@tonic-gate 		return (NULL);
4097c478bd9Sstevel@tonic-gate 	}
410*8f6d9daeSMarcel Telka 
4117c478bd9Sstevel@tonic-gate 	return (ma.m_uaddr);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * Returns a netconf structure from its internal list.  This
4167c478bd9Sstevel@tonic-gate  * structure should not be freed.
4177c478bd9Sstevel@tonic-gate  */
4187c478bd9Sstevel@tonic-gate struct netconfig *
419*8f6d9daeSMarcel Telka rpcbind_get_conf(char *netid)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	struct fdlist *fdl;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	for (fdl = fdhead; fdl; fdl = fdl->next)
4247c478bd9Sstevel@tonic-gate 		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
4257c478bd9Sstevel@tonic-gate 			break;
4267c478bd9Sstevel@tonic-gate 	if (fdl == NULL)
4277c478bd9Sstevel@tonic-gate 		return (NULL);
4287c478bd9Sstevel@tonic-gate 	return (fdl->nconf);
4297c478bd9Sstevel@tonic-gate }
430