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
is_multilevel(rpcprog_t prognum)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
__svc_free_xprtlist(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
svc_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const char * nettype)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 *
svc_tp_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const struct netconfig * nconf)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 *
svc_tli_create(const int fd,const struct netconfig * nconf,const struct t_bind * bindaddr,const uint_t sendsz,const uint_t recvsz)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 *
svc_tli_create_common(const int ofd,const struct netconfig * nconf,const struct t_bind * bindaddr,const uint_t sendsz,const uint_t recvsz,boolean_t mlp_flag)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