xref: /titanic_51/usr/src/lib/libnsl/rpc/svc_generic.c (revision 361f55a51b4e8a8d5a73478602f4afdc6e199da5)
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
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2161961e0fSrobinson 
227c478bd9Sstevel@tonic-gate /*
239ff75adeSSurya Prakki  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24*361f55a5SMarcel Telka  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T */
287c478bd9Sstevel@tonic-gate /*	All Rights Reserved   */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * svc_generic.c, Server side for RPC.
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "mt.h"
3661961e0fSrobinson #include <stdlib.h>
377c478bd9Sstevel@tonic-gate #include <sys/socket.h>
387c478bd9Sstevel@tonic-gate #include <netinet/in.h>
397c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
407c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
417c478bd9Sstevel@tonic-gate #include <inttypes.h>
427c478bd9Sstevel@tonic-gate #include "rpc_mt.h"
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <errno.h>
477c478bd9Sstevel@tonic-gate #include <syslog.h>
487c478bd9Sstevel@tonic-gate #include <rpc/nettype.h>
497c478bd9Sstevel@tonic-gate #include <malloc.h>
507c478bd9Sstevel@tonic-gate #include <string.h>
517c478bd9Sstevel@tonic-gate #include <stropts.h>
5245916cd2Sjpk #include <tsol/label.h>
5345916cd2Sjpk #include <nfs/nfs.h>
5445916cd2Sjpk #include <nfs/nfs_acl.h>
5545916cd2Sjpk #include <rpcsvc/mount.h>
5645916cd2Sjpk #include <rpcsvc/nsm_addr.h>
5745916cd2Sjpk #include <rpcsvc/rquota.h>
5845916cd2Sjpk #include <rpcsvc/sm_inter.h>
5945916cd2Sjpk #include <rpcsvc/nlm_prot.h>
607c478bd9Sstevel@tonic-gate 
6161961e0fSrobinson extern int __svc_vc_setflag(SVCXPRT *, int);
627c478bd9Sstevel@tonic-gate 
6361961e0fSrobinson extern SVCXPRT *svc_dg_create_private(int, uint_t, uint_t);
6461961e0fSrobinson extern SVCXPRT *svc_vc_create_private(int, uint_t, uint_t);
6561961e0fSrobinson extern SVCXPRT *svc_fd_create_private(int, uint_t, uint_t);
667c478bd9Sstevel@tonic-gate 
6761961e0fSrobinson extern bool_t __svc_add_to_xlist(SVCXPRT_LIST **, SVCXPRT *, mutex_t *);
6861961e0fSrobinson extern void __svc_free_xlist(SVCXPRT_LIST **, mutex_t *);
6961961e0fSrobinson 
7061961e0fSrobinson extern bool_t __rpc_try_doors(const char *, bool_t *);
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate  * The highest level interface for server creation.
747c478bd9Sstevel@tonic-gate  * It tries for all the nettokens in that particular class of token
757c478bd9Sstevel@tonic-gate  * and returns the number of handles it can create and/or find.
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * It creates a link list of all the handles it could create.
787c478bd9Sstevel@tonic-gate  * If svc_create() is called multiple times, it uses the handle
797c478bd9Sstevel@tonic-gate  * created earlier instead of creating a new handle every time.
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate SVCXPRT_LIST *_svc_xprtlist = NULL;
857c478bd9Sstevel@tonic-gate extern mutex_t xprtlist_lock;
867c478bd9Sstevel@tonic-gate 
8745916cd2Sjpk static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
8845916cd2Sjpk     const struct t_bind *, uint_t, uint_t, boolean_t);
8945916cd2Sjpk 
9045916cd2Sjpk boolean_t
9145916cd2Sjpk is_multilevel(rpcprog_t prognum)
9245916cd2Sjpk {
9345916cd2Sjpk 	/* This is a list of identified multilevel service provider */
9445916cd2Sjpk 	if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
9545916cd2Sjpk 	    (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
9645916cd2Sjpk 	    (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
9745916cd2Sjpk 	    (prognum == SM_PROG))
9845916cd2Sjpk 		return (B_TRUE);
9945916cd2Sjpk 
10045916cd2Sjpk 	return (B_FALSE);
10145916cd2Sjpk }
10245916cd2Sjpk 
1037c478bd9Sstevel@tonic-gate void
10461961e0fSrobinson __svc_free_xprtlist(void)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate 	__svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate int
11061961e0fSrobinson svc_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum,
11161961e0fSrobinson 							const char *nettype)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	SVCXPRT_LIST *l;
1147c478bd9Sstevel@tonic-gate 	int num = 0;
1157c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
1167c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
1177c478bd9Sstevel@tonic-gate 	void *handle;
1187c478bd9Sstevel@tonic-gate 	bool_t try_others;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/*
1217c478bd9Sstevel@tonic-gate 	 * Check if service should register over doors transport.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	if (__rpc_try_doors(nettype, &try_others)) {
1247c478bd9Sstevel@tonic-gate 		if (svc_door_create(dispatch, prognum, versnum, 0) == NULL)
1257c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
1267c478bd9Sstevel@tonic-gate 			    "svc_create: could not register over doors");
1277c478bd9Sstevel@tonic-gate 		else
1287c478bd9Sstevel@tonic-gate 			num++;
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 	if (!try_others)
1317c478bd9Sstevel@tonic-gate 		return (num);
1327c478bd9Sstevel@tonic-gate 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
1337c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "svc_create: unknown protocol");
1347c478bd9Sstevel@tonic-gate 		return (0);
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 	while (nconf = __rpc_getconf(handle)) {
13761961e0fSrobinson 		(void) mutex_lock(&xprtlist_lock);
1387c478bd9Sstevel@tonic-gate 		for (l = _svc_xprtlist; l; l = l->next) {
1397c478bd9Sstevel@tonic-gate 			if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
1409ff75adeSSurya Prakki 				/* Found an old one, use it */
1419ff75adeSSurya Prakki 				(void) rpcb_unset(prognum, versnum, nconf);
1427c478bd9Sstevel@tonic-gate 				if (svc_reg(l->xprt, prognum, versnum,
1437c478bd9Sstevel@tonic-gate 				    dispatch, nconf) == FALSE)
144*361f55a5SMarcel Telka 					(void) syslog(LOG_ERR, "svc_create: "
145*361f55a5SMarcel Telka 					    "could not register prog %d vers "
146*361f55a5SMarcel Telka 					    "%d on %s",
1477c478bd9Sstevel@tonic-gate 					    prognum, versnum, nconf->nc_netid);
1487c478bd9Sstevel@tonic-gate 				else
1497c478bd9Sstevel@tonic-gate 					num++;
1507c478bd9Sstevel@tonic-gate 				break;
1517c478bd9Sstevel@tonic-gate 			}
1527c478bd9Sstevel@tonic-gate 		}
15361961e0fSrobinson 		(void) mutex_unlock(&xprtlist_lock);
1547c478bd9Sstevel@tonic-gate 		if (l == NULL) {
1557c478bd9Sstevel@tonic-gate 			/* It was not found. Now create a new one */
1567c478bd9Sstevel@tonic-gate 			xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
1577c478bd9Sstevel@tonic-gate 			if (xprt) {
1587c478bd9Sstevel@tonic-gate 				if (!__svc_add_to_xlist(&_svc_xprtlist, xprt,
1597c478bd9Sstevel@tonic-gate 				    &xprtlist_lock)) {
1607c478bd9Sstevel@tonic-gate 					(void) syslog(LOG_ERR,
1617c478bd9Sstevel@tonic-gate 					    "svc_create: no memory");
1627c478bd9Sstevel@tonic-gate 					return (0);
1637c478bd9Sstevel@tonic-gate 				}
1647c478bd9Sstevel@tonic-gate 				num++;
1657c478bd9Sstevel@tonic-gate 			}
1667c478bd9Sstevel@tonic-gate 		}
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 	__rpc_endconf(handle);
1697c478bd9Sstevel@tonic-gate 	/*
1707c478bd9Sstevel@tonic-gate 	 * In case of num == 0; the error messages are generated by the
1717c478bd9Sstevel@tonic-gate 	 * underlying layers; and hence not needed here.
1727c478bd9Sstevel@tonic-gate 	 */
1737c478bd9Sstevel@tonic-gate 	return (num);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * The high level interface to svc_tli_create().
1787c478bd9Sstevel@tonic-gate  * It tries to create a server for "nconf" and registers the service
1797c478bd9Sstevel@tonic-gate  * with the rpcbind. It calls svc_tli_create();
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate SVCXPRT *
18261961e0fSrobinson svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
18361961e0fSrobinson 			const rpcvers_t versnum, const struct netconfig *nconf)
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt;
18645916cd2Sjpk 	boolean_t anon_mlp = B_FALSE;
1877c478bd9Sstevel@tonic-gate 
18861961e0fSrobinson 	if (nconf == NULL) {
189*361f55a5SMarcel Telka 		(void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
190*361f55a5SMarcel Telka 		    "structure for prog %d vers %d", prognum, versnum);
19161961e0fSrobinson 		return (NULL);
1927c478bd9Sstevel@tonic-gate 	}
19345916cd2Sjpk 
19445916cd2Sjpk 	/* Some programs need to allocate MLP for multilevel services */
19545916cd2Sjpk 	if (is_system_labeled() && is_multilevel(prognum))
19645916cd2Sjpk 		anon_mlp = B_TRUE;
19745916cd2Sjpk 	xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp);
19861961e0fSrobinson 	if (xprt == NULL)
19961961e0fSrobinson 		return (NULL);
2009acbbeafSnn35248 
2017c478bd9Sstevel@tonic-gate 	(void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
2027c478bd9Sstevel@tonic-gate 	if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
2037c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
2047c478bd9Sstevel@tonic-gate 		    "svc_tp_create: Could not register prog %d vers %d on %s",
2057c478bd9Sstevel@tonic-gate 		    prognum, versnum, nconf->nc_netid);
2067c478bd9Sstevel@tonic-gate 		SVC_DESTROY(xprt);
20761961e0fSrobinson 		return (NULL);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	return (xprt);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
21245916cd2Sjpk SVCXPRT *
21345916cd2Sjpk svc_tli_create(const int fd, const struct netconfig *nconf,
21445916cd2Sjpk     const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
21545916cd2Sjpk {
21645916cd2Sjpk 	return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
21745916cd2Sjpk }
21845916cd2Sjpk 
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate  * If fd is RPC_ANYFD, then it opens a fd for the given transport
2217c478bd9Sstevel@tonic-gate  * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
2227c478bd9Sstevel@tonic-gate  * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
2237c478bd9Sstevel@tonic-gate  * NULL bindadr and Connection oriented transports, the value of qlen
2247c478bd9Sstevel@tonic-gate  * is set arbitrarily.
2257c478bd9Sstevel@tonic-gate  *
2267c478bd9Sstevel@tonic-gate  * If sendsz or recvsz are zero, their default values are chosen.
2277c478bd9Sstevel@tonic-gate  */
2287c478bd9Sstevel@tonic-gate SVCXPRT *
22945916cd2Sjpk svc_tli_create_common(const int ofd, const struct netconfig *nconf,
23045916cd2Sjpk 	const struct t_bind *bindaddr, const uint_t sendsz,
23145916cd2Sjpk 	const uint_t recvsz, boolean_t mlp_flag)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	SVCXPRT *xprt = NULL;		/* service handle */
2347c478bd9Sstevel@tonic-gate 	struct t_info tinfo;		/* transport info */
2357c478bd9Sstevel@tonic-gate 	struct t_bind *tres = NULL;	/* bind info */
2367c478bd9Sstevel@tonic-gate 	bool_t madefd = FALSE;		/* whether fd opened here  */
2377c478bd9Sstevel@tonic-gate 	int state;			/* state of the transport provider */
23861961e0fSrobinson 	int fd = ofd;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (fd == RPC_ANYFD) {
24161961e0fSrobinson 		if (nconf == NULL) {
2427c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
2437c478bd9Sstevel@tonic-gate 			    "svc_tli_create: invalid netconfig");
24461961e0fSrobinson 			return (NULL);
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 		fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
2477c478bd9Sstevel@tonic-gate 		if (fd == -1) {
2487c478bd9Sstevel@tonic-gate 			char errorstr[100];
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 			__tli_sys_strerror(errorstr, sizeof (errorstr),
2517c478bd9Sstevel@tonic-gate 			    t_errno, errno);
252*361f55a5SMarcel Telka 			(void) syslog(LOG_ERR, "svc_tli_create: could not open "
253*361f55a5SMarcel Telka 			    "connection for %s: %s", nconf->nc_netid, errorstr);
25461961e0fSrobinson 			return (NULL);
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 		madefd = TRUE;
2577c478bd9Sstevel@tonic-gate 		state = T_UNBND;
2587c478bd9Sstevel@tonic-gate 	} else {
2597c478bd9Sstevel@tonic-gate 		/*
2607c478bd9Sstevel@tonic-gate 		 * It is an open descriptor. Sync it & get the transport info.
2617c478bd9Sstevel@tonic-gate 		 */
2627c478bd9Sstevel@tonic-gate 		if ((state = t_sync(fd)) == -1) {
2637c478bd9Sstevel@tonic-gate 			char errorstr[100];
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 			__tli_sys_strerror(errorstr, sizeof (errorstr),
2667c478bd9Sstevel@tonic-gate 			    t_errno, errno);
2677c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
2687c478bd9Sstevel@tonic-gate 			    "svc_tli_create: could not do t_sync: %s",
2697c478bd9Sstevel@tonic-gate 			    errorstr);
27061961e0fSrobinson 			return (NULL);
2717c478bd9Sstevel@tonic-gate 		}
2727c478bd9Sstevel@tonic-gate 		if (t_getinfo(fd, &tinfo) == -1) {
2737c478bd9Sstevel@tonic-gate 			char errorstr[100];
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 			__tli_sys_strerror(errorstr, sizeof (errorstr),
2767c478bd9Sstevel@tonic-gate 			    t_errno, errno);
277*361f55a5SMarcel Telka 			(void) syslog(LOG_ERR, "svc_tli_create: could not get "
278*361f55a5SMarcel Telka 			    "transport information: %s", errorstr);
27961961e0fSrobinson 			return (NULL);
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 		/* Enable options of returning the ip's for udp */
2827c478bd9Sstevel@tonic-gate 		if (nconf) {
2837c478bd9Sstevel@tonic-gate 			int ret = 0;
2847c478bd9Sstevel@tonic-gate 			if (strcmp(nconf->nc_netid, "udp6") == 0) {
2857c478bd9Sstevel@tonic-gate 				ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
2867c478bd9Sstevel@tonic-gate 				    IPV6_RECVPKTINFO, 1);
2877c478bd9Sstevel@tonic-gate 				if (ret < 0) {
2887c478bd9Sstevel@tonic-gate 					char errorstr[100];
2897c478bd9Sstevel@tonic-gate 
290*361f55a5SMarcel Telka 					__tli_sys_strerror(errorstr,
291*361f55a5SMarcel Telka 					    sizeof (errorstr), t_errno, errno);
2927c478bd9Sstevel@tonic-gate 					(void) syslog(LOG_ERR,
293*361f55a5SMarcel Telka 					    "svc_tli_create: "
294*361f55a5SMarcel Telka 					    "IPV6_RECVPKTINFO(1): %s",
2957c478bd9Sstevel@tonic-gate 					    errorstr);
29661961e0fSrobinson 					return (NULL);
2977c478bd9Sstevel@tonic-gate 				}
2987c478bd9Sstevel@tonic-gate 			} else if (strcmp(nconf->nc_netid, "udp") == 0) {
2997c478bd9Sstevel@tonic-gate 				ret = __rpc_tli_set_options(fd, IPPROTO_IP,
3007c478bd9Sstevel@tonic-gate 				    IP_RECVDSTADDR, 1);
3017c478bd9Sstevel@tonic-gate 				if (ret < 0) {
3027c478bd9Sstevel@tonic-gate 					char errorstr[100];
3037c478bd9Sstevel@tonic-gate 
304*361f55a5SMarcel Telka 					__tli_sys_strerror(errorstr,
305*361f55a5SMarcel Telka 					    sizeof (errorstr), t_errno, errno);
3067c478bd9Sstevel@tonic-gate 					(void) syslog(LOG_ERR,
307*361f55a5SMarcel Telka 					    "svc_tli_create: "
308*361f55a5SMarcel Telka 					    "IP_RECVDSTADDR(1): %s", errorstr);
30961961e0fSrobinson 					return (NULL);
3107c478bd9Sstevel@tonic-gate 				}
3117c478bd9Sstevel@tonic-gate 			}
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * If the fd is unbound, try to bind it.
3177c478bd9Sstevel@tonic-gate 	 * In any case, try to get its bound info in tres
3187c478bd9Sstevel@tonic-gate 	 */
3197c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3207c478bd9Sstevel@tonic-gate 	tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
3217c478bd9Sstevel@tonic-gate 	if (tres == NULL) {
3227c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "svc_tli_create: No memory!");
3237c478bd9Sstevel@tonic-gate 		goto freedata;
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	switch (state) {
3277c478bd9Sstevel@tonic-gate 		bool_t tcp, exclbind;
3287c478bd9Sstevel@tonic-gate 	case T_UNBND:
32945916cd2Sjpk 		/* If this is a labeled system, then ask for an MLP */
33045916cd2Sjpk 		if (is_system_labeled() &&
33145916cd2Sjpk 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
33245916cd2Sjpk 		    strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
33345916cd2Sjpk 			(void) __rpc_tli_set_options(fd, SOL_SOCKET,
33445916cd2Sjpk 			    SO_RECVUCRED, 1);
33545916cd2Sjpk 			if (mlp_flag)
33645916cd2Sjpk 				(void) __rpc_tli_set_options(fd, SOL_SOCKET,
33745916cd2Sjpk 				    SO_ANON_MLP, 1);
33845916cd2Sjpk 		}
33945916cd2Sjpk 
3407c478bd9Sstevel@tonic-gate 		/*
341ae347574Skcpoon 		 * SO_EXCLBIND has the following properties
3427c478bd9Sstevel@tonic-gate 		 *    - an fd bound to port P via IPv4 will prevent an IPv6
3437c478bd9Sstevel@tonic-gate 		 *    bind to port P (and vice versa)
3447c478bd9Sstevel@tonic-gate 		 *    - an fd bound to a wildcard IP address for port P will
3457c478bd9Sstevel@tonic-gate 		 *    prevent a more specific IP address bind to port P
3467c478bd9Sstevel@tonic-gate 		 *    (see {tcp,udp}.c for details)
3477c478bd9Sstevel@tonic-gate 		 *
3487c478bd9Sstevel@tonic-gate 		 * We use the latter property to prevent hijacking of RPC
3497c478bd9Sstevel@tonic-gate 		 * services that reside at non-privileged ports.
3507c478bd9Sstevel@tonic-gate 		 */
3517c478bd9Sstevel@tonic-gate 		tcp = nconf ? (strcmp(nconf->nc_proto, NC_TCP) == 0) : 0;
3527c478bd9Sstevel@tonic-gate 		if (nconf &&
3537c478bd9Sstevel@tonic-gate 		    (tcp || (strcmp(nconf->nc_proto, NC_UDP) == 0)) &&
3547c478bd9Sstevel@tonic-gate 		    rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind)) {
3557c478bd9Sstevel@tonic-gate 			if (exclbind) {
356ae347574Skcpoon 				if (__rpc_tli_set_options(fd, SOL_SOCKET,
357ae347574Skcpoon 				    SO_EXCLBIND, 1) < 0) {
3587c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
3597c478bd9Sstevel@tonic-gate 			    "svc_tli_create: can't set EXCLBIND [netid='%s']",
3607c478bd9Sstevel@tonic-gate 					    nconf->nc_netid);
3617c478bd9Sstevel@tonic-gate 					goto freedata;
3627c478bd9Sstevel@tonic-gate 				}
3637c478bd9Sstevel@tonic-gate 			}
3647c478bd9Sstevel@tonic-gate 		}
3657c478bd9Sstevel@tonic-gate 		if (bindaddr) {
366*361f55a5SMarcel Telka 			if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
3677c478bd9Sstevel@tonic-gate 				char errorstr[100];
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 				__tli_sys_strerror(errorstr, sizeof (errorstr),
3707c478bd9Sstevel@tonic-gate 				    t_errno, errno);
3717c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR,
3727c478bd9Sstevel@tonic-gate 				    "svc_tli_create: could not bind: %s",
3737c478bd9Sstevel@tonic-gate 				    errorstr);
3747c478bd9Sstevel@tonic-gate 				goto freedata;
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate 			/*
3777c478bd9Sstevel@tonic-gate 			 * Should compare the addresses only if addr.len
3787c478bd9Sstevel@tonic-gate 			 * was non-zero
3797c478bd9Sstevel@tonic-gate 			 */
3807c478bd9Sstevel@tonic-gate 			if (bindaddr->addr.len &&
3817c478bd9Sstevel@tonic-gate 			    (memcmp(bindaddr->addr.buf, tres->addr.buf,
3827c478bd9Sstevel@tonic-gate 			    (int)tres->addr.len) != 0)) {
383*361f55a5SMarcel Telka 				(void) syslog(LOG_ERR, "svc_tli_create: could "
384*361f55a5SMarcel Telka 				    "not bind to requested address: address "
385*361f55a5SMarcel Telka 				    "mismatch");
3867c478bd9Sstevel@tonic-gate 				goto freedata;
3877c478bd9Sstevel@tonic-gate 			}
3887c478bd9Sstevel@tonic-gate 		} else {
389*361f55a5SMarcel Telka 			if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
390*361f55a5SMarcel Telka 			    == FALSE) {
391*361f55a5SMarcel Telka 				syslog(LOG_ERR,
392*361f55a5SMarcel Telka 				    "svc_tli_create: can't get listen backlog");
393*361f55a5SMarcel Telka 				goto freedata;
394*361f55a5SMarcel Telka 			}
3957c478bd9Sstevel@tonic-gate 			tres->addr.len = 0;
3967c478bd9Sstevel@tonic-gate 			if (t_bind(fd, tres, tres) == -1) {
3977c478bd9Sstevel@tonic-gate 				char errorstr[100];
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 				__tli_sys_strerror(errorstr, sizeof (errorstr),
4007c478bd9Sstevel@tonic-gate 				    t_errno, errno);
4017c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR,
4027c478bd9Sstevel@tonic-gate 				    "svc_tli_create: could not bind: %s",
4037c478bd9Sstevel@tonic-gate 				    errorstr);
4047c478bd9Sstevel@tonic-gate 				goto freedata;
4057c478bd9Sstevel@tonic-gate 			}
4067c478bd9Sstevel@tonic-gate 		}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 		/* Enable options of returning the ip's for udp */
4097c478bd9Sstevel@tonic-gate 		if (nconf) {
4107c478bd9Sstevel@tonic-gate 			int ret = 0;
4117c478bd9Sstevel@tonic-gate 			if (strcmp(nconf->nc_netid, "udp6") == 0) {
4127c478bd9Sstevel@tonic-gate 				ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
4137c478bd9Sstevel@tonic-gate 				    IPV6_RECVPKTINFO, 1);
4147c478bd9Sstevel@tonic-gate 				if (ret < 0) {
4157c478bd9Sstevel@tonic-gate 					char errorstr[100];
4167c478bd9Sstevel@tonic-gate 
417*361f55a5SMarcel Telka 					__tli_sys_strerror(errorstr,
418*361f55a5SMarcel Telka 					    sizeof (errorstr), t_errno, errno);
4197c478bd9Sstevel@tonic-gate 					(void) syslog(LOG_ERR,
420*361f55a5SMarcel Telka 					    "svc_tli_create: "
421*361f55a5SMarcel Telka 					    "IPV6_RECVPKTINFO(2): %s",
4227c478bd9Sstevel@tonic-gate 					    errorstr);
4237c478bd9Sstevel@tonic-gate 					goto freedata;
4247c478bd9Sstevel@tonic-gate 				}
4257c478bd9Sstevel@tonic-gate 			} else if (strcmp(nconf->nc_netid, "udp") == 0) {
4267c478bd9Sstevel@tonic-gate 				ret = __rpc_tli_set_options(fd, IPPROTO_IP,
4277c478bd9Sstevel@tonic-gate 				    IP_RECVDSTADDR, 1);
4287c478bd9Sstevel@tonic-gate 				if (ret < 0) {
4297c478bd9Sstevel@tonic-gate 					char errorstr[100];
4307c478bd9Sstevel@tonic-gate 
431*361f55a5SMarcel Telka 					__tli_sys_strerror(errorstr,
432*361f55a5SMarcel Telka 					    sizeof (errorstr), t_errno, errno);
4337c478bd9Sstevel@tonic-gate 					(void) syslog(LOG_ERR,
434*361f55a5SMarcel Telka 					    "svc_tli_create: "
435*361f55a5SMarcel Telka 					    "IP_RECVDSTADDR(2): %s", errorstr);
4367c478bd9Sstevel@tonic-gate 					goto freedata;
4377c478bd9Sstevel@tonic-gate 				}
4387c478bd9Sstevel@tonic-gate 			}
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 		break;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	case T_IDLE:
4437c478bd9Sstevel@tonic-gate 		if (bindaddr) {
4447c478bd9Sstevel@tonic-gate 			/* Copy the entire stuff in tres */
4457c478bd9Sstevel@tonic-gate 			if (tres->addr.maxlen < bindaddr->addr.len) {
4467c478bd9Sstevel@tonic-gate 				(void) syslog(LOG_ERR,
4477c478bd9Sstevel@tonic-gate 				"svc_tli_create: illegal netbuf length");
4487c478bd9Sstevel@tonic-gate 				goto freedata;
4497c478bd9Sstevel@tonic-gate 			}
4507c478bd9Sstevel@tonic-gate 			tres->addr.len = bindaddr->addr.len;
4517c478bd9Sstevel@tonic-gate 			(void) memcpy(tres->addr.buf, bindaddr->addr.buf,
4527c478bd9Sstevel@tonic-gate 			    (int)tres->addr.len);
4537c478bd9Sstevel@tonic-gate 		} else
4547c478bd9Sstevel@tonic-gate 			if (t_getname(fd, &(tres->addr), LOCALNAME) == -1)
4557c478bd9Sstevel@tonic-gate 				tres->addr.len = 0;
4567c478bd9Sstevel@tonic-gate 		break;
4577c478bd9Sstevel@tonic-gate 	case T_INREL:
4587c478bd9Sstevel@tonic-gate 		(void) t_rcvrel(fd);
4597c478bd9Sstevel@tonic-gate 		(void) t_sndrel(fd);
460*361f55a5SMarcel Telka 		(void) syslog(LOG_ERR, "svc_tli_create: other side wants to "
461*361f55a5SMarcel Telka 		    "release connection");
4627c478bd9Sstevel@tonic-gate 		goto freedata;
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	case T_INCON:
4657c478bd9Sstevel@tonic-gate 		/* Do nothing here. Assume this is handled in rendezvous */
4667c478bd9Sstevel@tonic-gate 		break;
4677c478bd9Sstevel@tonic-gate 	case T_DATAXFER:
4687c478bd9Sstevel@tonic-gate 		/*
4697c478bd9Sstevel@tonic-gate 		 * This takes care of the case where a fd
4707c478bd9Sstevel@tonic-gate 		 * is passed on which a connection has already
4717c478bd9Sstevel@tonic-gate 		 * been accepted.
4727c478bd9Sstevel@tonic-gate 		 */
4737c478bd9Sstevel@tonic-gate 		if (t_getname(fd, &(tres->addr), LOCALNAME) == -1)
4747c478bd9Sstevel@tonic-gate 			tres->addr.len = 0;
4757c478bd9Sstevel@tonic-gate 		break;
4767c478bd9Sstevel@tonic-gate 	default:
4777c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR,
4787c478bd9Sstevel@tonic-gate 		    "svc_tli_create: connection in a wierd state (%d)", state);
4797c478bd9Sstevel@tonic-gate 		goto freedata;
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/*
4837c478bd9Sstevel@tonic-gate 	 * call transport specific function.
4847c478bd9Sstevel@tonic-gate 	 */
4857c478bd9Sstevel@tonic-gate 	switch (tinfo.servtype) {
4867c478bd9Sstevel@tonic-gate 		case T_COTS_ORD:
4877c478bd9Sstevel@tonic-gate 		case T_COTS:
4887c478bd9Sstevel@tonic-gate 			if (state == T_DATAXFER)
4897c478bd9Sstevel@tonic-gate 				xprt = svc_fd_create_private(fd, sendsz,
4907c478bd9Sstevel@tonic-gate 				    recvsz);
4917c478bd9Sstevel@tonic-gate 			else
4927c478bd9Sstevel@tonic-gate 				xprt = svc_vc_create_private(fd, sendsz,
4937c478bd9Sstevel@tonic-gate 				    recvsz);
4947c478bd9Sstevel@tonic-gate 			if (!nconf || !xprt)
4957c478bd9Sstevel@tonic-gate 				break;
4967c478bd9Sstevel@tonic-gate 			if ((tinfo.servtype == T_COTS_ORD) &&
4977c478bd9Sstevel@tonic-gate 			    (state != T_DATAXFER) &&
4987c478bd9Sstevel@tonic-gate 			    (strcmp(nconf->nc_protofmly, "inet") == 0))
4997c478bd9Sstevel@tonic-gate 				(void) __svc_vc_setflag(xprt, TRUE);
5007c478bd9Sstevel@tonic-gate 			break;
5017c478bd9Sstevel@tonic-gate 		case T_CLTS:
5027c478bd9Sstevel@tonic-gate 			xprt = svc_dg_create_private(fd, sendsz, recvsz);
5037c478bd9Sstevel@tonic-gate 			break;
5047c478bd9Sstevel@tonic-gate 		default:
5057c478bd9Sstevel@tonic-gate 			(void) syslog(LOG_ERR,
5067c478bd9Sstevel@tonic-gate 			    "svc_tli_create: bad service type");
5077c478bd9Sstevel@tonic-gate 			goto freedata;
5087c478bd9Sstevel@tonic-gate 	}
50961961e0fSrobinson 	if (xprt == NULL)
5107c478bd9Sstevel@tonic-gate 		/*
5117c478bd9Sstevel@tonic-gate 		 * The error messages here are spitted out by the lower layers:
5127c478bd9Sstevel@tonic-gate 		 * svc_vc_create(), svc_fd_create() and svc_dg_create().
5137c478bd9Sstevel@tonic-gate 		 */
5147c478bd9Sstevel@tonic-gate 		goto freedata;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/* fill in the other xprt information */
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/* Assign the local bind address */
5197c478bd9Sstevel@tonic-gate 	xprt->xp_ltaddr = tres->addr;
5207c478bd9Sstevel@tonic-gate 	/* Fill in type of service */
5217c478bd9Sstevel@tonic-gate 	xprt->xp_type = tinfo.servtype;
5227c478bd9Sstevel@tonic-gate 	tres->addr.buf = NULL;
5237c478bd9Sstevel@tonic-gate 	(void) t_free((char *)tres, T_BIND);
5247c478bd9Sstevel@tonic-gate 	tres = NULL;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	xprt->xp_rtaddr.len = 0;
5277c478bd9Sstevel@tonic-gate 	xprt->xp_rtaddr.maxlen = __rpc_get_a_size(tinfo.addr);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/* Allocate space for the remote bind info */
53061961e0fSrobinson 	if ((xprt->xp_rtaddr.buf = malloc(xprt->xp_rtaddr.maxlen)) == NULL) {
5317c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "svc_tli_create: No memory!");
5327c478bd9Sstevel@tonic-gate 		goto freedata;
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (nconf) {
5367c478bd9Sstevel@tonic-gate 		xprt->xp_netid = strdup(nconf->nc_netid);
5377c478bd9Sstevel@tonic-gate 		if (xprt->xp_netid == NULL) {
5387c478bd9Sstevel@tonic-gate 			if (xprt->xp_rtaddr.buf)
5397c478bd9Sstevel@tonic-gate 				free(xprt->xp_rtaddr.buf);
5407c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "svc_tli_create: strdup failed!");
5417c478bd9Sstevel@tonic-gate 			goto freedata;
5427c478bd9Sstevel@tonic-gate 		}
5437c478bd9Sstevel@tonic-gate 		xprt->xp_tp = strdup(nconf->nc_device);
5447c478bd9Sstevel@tonic-gate 		if (xprt->xp_tp == NULL) {
5457c478bd9Sstevel@tonic-gate 			if (xprt->xp_rtaddr.buf)
5467c478bd9Sstevel@tonic-gate 				free(xprt->xp_rtaddr.buf);
5477c478bd9Sstevel@tonic-gate 			if (xprt->xp_netid)
5487c478bd9Sstevel@tonic-gate 				free(xprt->xp_netid);
5497c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "svc_tli_create: strdup failed!");
5507c478bd9Sstevel@tonic-gate 			goto freedata;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate /*
5557c478bd9Sstevel@tonic-gate  *	if (madefd && (tinfo.servtype == T_CLTS))
55661961e0fSrobinson  *		(void) ioctl(fd, I_POP, NULL);
5577c478bd9Sstevel@tonic-gate  */
5587c478bd9Sstevel@tonic-gate 	xprt_register(xprt);
5597c478bd9Sstevel@tonic-gate 	return (xprt);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate freedata:
5627c478bd9Sstevel@tonic-gate 	if (madefd)
5637c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
5647c478bd9Sstevel@tonic-gate 	if (tres)
5657c478bd9Sstevel@tonic-gate 		(void) t_free((char *)tres, T_BIND);
5667c478bd9Sstevel@tonic-gate 	if (xprt) {
5677c478bd9Sstevel@tonic-gate 		if (!madefd) /* so that svc_destroy doesnt close fd */
5687c478bd9Sstevel@tonic-gate 			xprt->xp_fd = RPC_ANYFD;
5697c478bd9Sstevel@tonic-gate 		SVC_DESTROY(xprt);
5707c478bd9Sstevel@tonic-gate 	}
57161961e0fSrobinson 	return (NULL);
5727c478bd9Sstevel@tonic-gate }
573