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 /*
23*dec98d2aSGordon Ross * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
249ff75adeSSurya Prakki * Copyright (c) 1989, 2010, Oracle and/or its affiliates. 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
90*dec98d2aSGordon Ross static SVCXPRT *svc_tp_create_bind(void (*dispatch)(),
91*dec98d2aSGordon Ross const rpcprog_t, const rpcvers_t,
92*dec98d2aSGordon Ross const struct netconfig *, const struct t_bind *);
93*dec98d2aSGordon Ross
9445916cd2Sjpk boolean_t
is_multilevel(rpcprog_t prognum)9545916cd2Sjpk is_multilevel(rpcprog_t prognum)
9645916cd2Sjpk {
9745916cd2Sjpk /* This is a list of identified multilevel service provider */
9845916cd2Sjpk if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
9945916cd2Sjpk (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
10045916cd2Sjpk (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
10145916cd2Sjpk (prognum == SM_PROG))
10245916cd2Sjpk return (B_TRUE);
10345916cd2Sjpk
10445916cd2Sjpk return (B_FALSE);
10545916cd2Sjpk }
10645916cd2Sjpk
1077c478bd9Sstevel@tonic-gate void
__svc_free_xprtlist(void)10861961e0fSrobinson __svc_free_xprtlist(void)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate int
svc_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const char * nettype)11461961e0fSrobinson svc_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum,
11561961e0fSrobinson const char *nettype)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate SVCXPRT_LIST *l;
1187c478bd9Sstevel@tonic-gate int num = 0;
1197c478bd9Sstevel@tonic-gate SVCXPRT *xprt;
1207c478bd9Sstevel@tonic-gate struct netconfig *nconf;
1217c478bd9Sstevel@tonic-gate void *handle;
1227c478bd9Sstevel@tonic-gate bool_t try_others;
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate * Check if service should register over doors transport.
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate if (__rpc_try_doors(nettype, &try_others)) {
1287c478bd9Sstevel@tonic-gate if (svc_door_create(dispatch, prognum, versnum, 0) == NULL)
1297c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
130361f55a5SMarcel Telka "svc_create: could not register over doors");
1317c478bd9Sstevel@tonic-gate else
1327c478bd9Sstevel@tonic-gate num++;
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate if (!try_others)
1357c478bd9Sstevel@tonic-gate return (num);
1367c478bd9Sstevel@tonic-gate if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
1377c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svc_create: unknown protocol");
1387c478bd9Sstevel@tonic-gate return (0);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate while (nconf = __rpc_getconf(handle)) {
14161961e0fSrobinson (void) mutex_lock(&xprtlist_lock);
1427c478bd9Sstevel@tonic-gate for (l = _svc_xprtlist; l; l = l->next) {
1437c478bd9Sstevel@tonic-gate if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
1449ff75adeSSurya Prakki /* Found an old one, use it */
1459ff75adeSSurya Prakki (void) rpcb_unset(prognum, versnum, nconf);
1467c478bd9Sstevel@tonic-gate if (svc_reg(l->xprt, prognum, versnum,
147361f55a5SMarcel Telka dispatch, nconf) == FALSE)
148361f55a5SMarcel Telka (void) syslog(LOG_ERR, "svc_create: "
149361f55a5SMarcel Telka "could not register prog %d vers "
150361f55a5SMarcel Telka "%d on %s",
151361f55a5SMarcel Telka prognum, versnum, nconf->nc_netid);
1527c478bd9Sstevel@tonic-gate else
1537c478bd9Sstevel@tonic-gate num++;
1547c478bd9Sstevel@tonic-gate break;
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate }
15761961e0fSrobinson (void) mutex_unlock(&xprtlist_lock);
1587c478bd9Sstevel@tonic-gate if (l == NULL) {
1597c478bd9Sstevel@tonic-gate /* It was not found. Now create a new one */
1607c478bd9Sstevel@tonic-gate xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
1617c478bd9Sstevel@tonic-gate if (xprt) {
1627c478bd9Sstevel@tonic-gate if (!__svc_add_to_xlist(&_svc_xprtlist, xprt,
163361f55a5SMarcel Telka &xprtlist_lock)) {
1647c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
165361f55a5SMarcel Telka "svc_create: no memory");
1667c478bd9Sstevel@tonic-gate return (0);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate num++;
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate __rpc_endconf(handle);
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate * In case of num == 0; the error messages are generated by the
1757c478bd9Sstevel@tonic-gate * underlying layers; and hence not needed here.
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate return (num);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * The high level interface to svc_tli_create().
1827c478bd9Sstevel@tonic-gate * It tries to create a server for "nconf" and registers the service
183*dec98d2aSGordon Ross * with the rpcbind.
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate SVCXPRT *
svc_tp_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const struct netconfig * nconf)18661961e0fSrobinson svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
187*dec98d2aSGordon Ross const rpcvers_t versnum, const struct netconfig *nconf)
188*dec98d2aSGordon Ross {
189*dec98d2aSGordon Ross return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL));
190*dec98d2aSGordon Ross }
191*dec98d2aSGordon Ross
192*dec98d2aSGordon Ross /*
193*dec98d2aSGordon Ross * svc_tp_create_addr()
194*dec98d2aSGordon Ross * Variant of svc_tp_create() that allows specifying just the
195*dec98d2aSGordon Ross * the binding address, for convenience.
196*dec98d2aSGordon Ross */
197*dec98d2aSGordon Ross SVCXPRT *
svc_tp_create_addr(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const struct netconfig * nconf,const struct netbuf * addr)198*dec98d2aSGordon Ross svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum,
199*dec98d2aSGordon Ross const rpcvers_t versnum, const struct netconfig *nconf,
200*dec98d2aSGordon Ross const struct netbuf *addr)
201*dec98d2aSGordon Ross {
202*dec98d2aSGordon Ross struct t_bind bind;
203*dec98d2aSGordon Ross struct t_bind *bindp = NULL;
204*dec98d2aSGordon Ross
205*dec98d2aSGordon Ross if (addr != NULL) {
206*dec98d2aSGordon Ross
207*dec98d2aSGordon Ross bind.addr = *addr;
208*dec98d2aSGordon Ross if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) {
209*dec98d2aSGordon Ross syslog(LOG_ERR,
210*dec98d2aSGordon Ross "svc_tp_create: can't get listen backlog");
211*dec98d2aSGordon Ross return (NULL);
212*dec98d2aSGordon Ross }
213*dec98d2aSGordon Ross bindp = &bind;
214*dec98d2aSGordon Ross }
215*dec98d2aSGordon Ross
216*dec98d2aSGordon Ross /*
217*dec98d2aSGordon Ross * When bindp == NULL, this is the same as svc_tp_create().
218*dec98d2aSGordon Ross */
219*dec98d2aSGordon Ross return (svc_tp_create_bind(dispatch, prognum, versnum,
220*dec98d2aSGordon Ross nconf, bindp));
221*dec98d2aSGordon Ross }
222*dec98d2aSGordon Ross
223*dec98d2aSGordon Ross static SVCXPRT *
svc_tp_create_bind(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const struct netconfig * nconf,const struct t_bind * bindaddr)224*dec98d2aSGordon Ross svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum,
225*dec98d2aSGordon Ross const rpcvers_t versnum, const struct netconfig *nconf,
226*dec98d2aSGordon Ross const struct t_bind *bindaddr)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate SVCXPRT *xprt;
22945916cd2Sjpk boolean_t anon_mlp = B_FALSE;
2307c478bd9Sstevel@tonic-gate
23161961e0fSrobinson if (nconf == NULL) {
232361f55a5SMarcel Telka (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
233361f55a5SMarcel Telka "structure for prog %d vers %d", prognum, versnum);
23461961e0fSrobinson return (NULL);
2357c478bd9Sstevel@tonic-gate }
23645916cd2Sjpk
23745916cd2Sjpk /* Some programs need to allocate MLP for multilevel services */
23845916cd2Sjpk if (is_system_labeled() && is_multilevel(prognum))
23945916cd2Sjpk anon_mlp = B_TRUE;
240*dec98d2aSGordon Ross xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0,
241*dec98d2aSGordon Ross anon_mlp);
24261961e0fSrobinson if (xprt == NULL)
24361961e0fSrobinson return (NULL);
2449acbbeafSnn
2459ff75adeSSurya Prakki (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
2467c478bd9Sstevel@tonic-gate if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
2477c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
248361f55a5SMarcel Telka "svc_tp_create: Could not register prog %d vers %d on %s",
249361f55a5SMarcel Telka prognum, versnum, nconf->nc_netid);
2507c478bd9Sstevel@tonic-gate SVC_DESTROY(xprt);
25161961e0fSrobinson return (NULL);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate return (xprt);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate
25645916cd2Sjpk SVCXPRT *
svc_tli_create(const int fd,const struct netconfig * nconf,const struct t_bind * bindaddr,const uint_t sendsz,const uint_t recvsz)25745916cd2Sjpk svc_tli_create(const int fd, const struct netconfig *nconf,
25845916cd2Sjpk const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
25945916cd2Sjpk {
26045916cd2Sjpk return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
26145916cd2Sjpk }
26245916cd2Sjpk
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate * If fd is RPC_ANYFD, then it opens a fd for the given transport
2657c478bd9Sstevel@tonic-gate * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
2667c478bd9Sstevel@tonic-gate * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
2677c478bd9Sstevel@tonic-gate * NULL bindadr and Connection oriented transports, the value of qlen
2687c478bd9Sstevel@tonic-gate * is set arbitrarily.
2697c478bd9Sstevel@tonic-gate *
2707c478bd9Sstevel@tonic-gate * If sendsz or recvsz are zero, their default values are chosen.
2717c478bd9Sstevel@tonic-gate */
2727c478bd9Sstevel@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)27345916cd2Sjpk svc_tli_create_common(const int ofd, const struct netconfig *nconf,
27445916cd2Sjpk const struct t_bind *bindaddr, const uint_t sendsz,
27545916cd2Sjpk const uint_t recvsz, boolean_t mlp_flag)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate SVCXPRT *xprt = NULL; /* service handle */
2787c478bd9Sstevel@tonic-gate struct t_info tinfo; /* transport info */
2797c478bd9Sstevel@tonic-gate struct t_bind *tres = NULL; /* bind info */
2807c478bd9Sstevel@tonic-gate bool_t madefd = FALSE; /* whether fd opened here */
2817c478bd9Sstevel@tonic-gate int state; /* state of the transport provider */
28261961e0fSrobinson int fd = ofd;
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate if (fd == RPC_ANYFD) {
28561961e0fSrobinson if (nconf == NULL) {
2867c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
2877c478bd9Sstevel@tonic-gate "svc_tli_create: invalid netconfig");
28861961e0fSrobinson return (NULL);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
2917c478bd9Sstevel@tonic-gate if (fd == -1) {
2927c478bd9Sstevel@tonic-gate char errorstr[100];
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate __tli_sys_strerror(errorstr, sizeof (errorstr),
295361f55a5SMarcel Telka t_errno, errno);
296361f55a5SMarcel Telka (void) syslog(LOG_ERR, "svc_tli_create: could not open "
297361f55a5SMarcel Telka "connection for %s: %s", nconf->nc_netid, errorstr);
29861961e0fSrobinson return (NULL);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate madefd = TRUE;
3017c478bd9Sstevel@tonic-gate state = T_UNBND;
3027c478bd9Sstevel@tonic-gate } else {
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate * It is an open descriptor. Sync it & get the transport info.
3057c478bd9Sstevel@tonic-gate */
3067c478bd9Sstevel@tonic-gate if ((state = t_sync(fd)) == -1) {
3077c478bd9Sstevel@tonic-gate char errorstr[100];
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate __tli_sys_strerror(errorstr, sizeof (errorstr),
310361f55a5SMarcel Telka t_errno, errno);
3117c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
312361f55a5SMarcel Telka "svc_tli_create: could not do t_sync: %s",
313361f55a5SMarcel Telka errorstr);
31461961e0fSrobinson return (NULL);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate if (t_getinfo(fd, &tinfo) == -1) {
3177c478bd9Sstevel@tonic-gate char errorstr[100];
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate __tli_sys_strerror(errorstr, sizeof (errorstr),
320361f55a5SMarcel Telka t_errno, errno);
321361f55a5SMarcel Telka (void) syslog(LOG_ERR, "svc_tli_create: could not get "
322361f55a5SMarcel Telka "transport information: %s", errorstr);
32361961e0fSrobinson return (NULL);
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate /* Enable options of returning the ip's for udp */
3267c478bd9Sstevel@tonic-gate if (nconf) {
327361f55a5SMarcel Telka int ret = 0;
328361f55a5SMarcel Telka if (strcmp(nconf->nc_netid, "udp6") == 0) {
329361f55a5SMarcel Telka ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
330361f55a5SMarcel Telka IPV6_RECVPKTINFO, 1);
331361f55a5SMarcel Telka if (ret < 0) {
332361f55a5SMarcel Telka char errorstr[100];
333361f55a5SMarcel Telka
334361f55a5SMarcel Telka __tli_sys_strerror(errorstr,
335361f55a5SMarcel Telka sizeof (errorstr), t_errno, errno);
336361f55a5SMarcel Telka (void) syslog(LOG_ERR,
337361f55a5SMarcel Telka "svc_tli_create: "
338361f55a5SMarcel Telka "IPV6_RECVPKTINFO(1): %s",
339361f55a5SMarcel Telka errorstr);
340361f55a5SMarcel Telka return (NULL);
341361f55a5SMarcel Telka }
342361f55a5SMarcel Telka } else if (strcmp(nconf->nc_netid, "udp") == 0) {
343361f55a5SMarcel Telka ret = __rpc_tli_set_options(fd, IPPROTO_IP,
344361f55a5SMarcel Telka IP_RECVDSTADDR, 1);
345361f55a5SMarcel Telka if (ret < 0) {
346361f55a5SMarcel Telka char errorstr[100];
347361f55a5SMarcel Telka
348361f55a5SMarcel Telka __tli_sys_strerror(errorstr,
349361f55a5SMarcel Telka sizeof (errorstr), t_errno, errno);
350361f55a5SMarcel Telka (void) syslog(LOG_ERR,
351361f55a5SMarcel Telka "svc_tli_create: "
352361f55a5SMarcel Telka "IP_RECVDSTADDR(1): %s", errorstr);
353361f55a5SMarcel Telka return (NULL);
354361f55a5SMarcel Telka }
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate * If the fd is unbound, try to bind it.
3617c478bd9Sstevel@tonic-gate * In any case, try to get its bound info in tres
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
3647c478bd9Sstevel@tonic-gate tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
3657c478bd9Sstevel@tonic-gate if (tres == NULL) {
3667c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
3677c478bd9Sstevel@tonic-gate goto freedata;
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate switch (state) {
3717c478bd9Sstevel@tonic-gate case T_UNBND:
37245916cd2Sjpk /* If this is a labeled system, then ask for an MLP */
37345916cd2Sjpk if (is_system_labeled() &&
37445916cd2Sjpk (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
37545916cd2Sjpk strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
37645916cd2Sjpk (void) __rpc_tli_set_options(fd, SOL_SOCKET,
37745916cd2Sjpk SO_RECVUCRED, 1);
37845916cd2Sjpk if (mlp_flag)
37945916cd2Sjpk (void) __rpc_tli_set_options(fd, SOL_SOCKET,
38045916cd2Sjpk SO_ANON_MLP, 1);
38145916cd2Sjpk }
38245916cd2Sjpk
3837c478bd9Sstevel@tonic-gate if (bindaddr) {
384*dec98d2aSGordon Ross /*
385*dec98d2aSGordon Ross * Services that specify a bind address typically
386*dec98d2aSGordon Ross * use a fixed service (IP port) so we need to set
387*dec98d2aSGordon Ross * SO_REUSEADDR to prevent bind errors on restart.
388*dec98d2aSGordon Ross */
389*dec98d2aSGordon Ross if (bindaddr->addr.len != 0)
390*dec98d2aSGordon Ross (void) __rpc_tli_set_options(fd, SOL_SOCKET,
391*dec98d2aSGordon Ross SO_REUSEADDR, 1);
392361f55a5SMarcel Telka if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
3937c478bd9Sstevel@tonic-gate char errorstr[100];
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate __tli_sys_strerror(errorstr, sizeof (errorstr),
396361f55a5SMarcel Telka t_errno, errno);
3977c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
398361f55a5SMarcel Telka "svc_tli_create: could not bind: %s",
399361f55a5SMarcel Telka errorstr);
4007c478bd9Sstevel@tonic-gate goto freedata;
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate * Should compare the addresses only if addr.len
4047c478bd9Sstevel@tonic-gate * was non-zero
4057c478bd9Sstevel@tonic-gate */
4067c478bd9Sstevel@tonic-gate if (bindaddr->addr.len &&
407361f55a5SMarcel Telka (memcmp(bindaddr->addr.buf, tres->addr.buf,
408361f55a5SMarcel Telka (int)tres->addr.len) != 0)) {
409361f55a5SMarcel Telka (void) syslog(LOG_ERR, "svc_tli_create: could "
410361f55a5SMarcel Telka "not bind to requested address: address "
411361f55a5SMarcel Telka "mismatch");
4127c478bd9Sstevel@tonic-gate goto freedata;
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate } else {
415361f55a5SMarcel Telka if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
416361f55a5SMarcel Telka == FALSE) {
417361f55a5SMarcel Telka syslog(LOG_ERR,
418361f55a5SMarcel Telka "svc_tli_create: can't get listen backlog");
419361f55a5SMarcel Telka goto freedata;
420361f55a5SMarcel Telka }
4217c478bd9Sstevel@tonic-gate tres->addr.len = 0;
4227c478bd9Sstevel@tonic-gate if (t_bind(fd, tres, tres) == -1) {
4237c478bd9Sstevel@tonic-gate char errorstr[100];
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate __tli_sys_strerror(errorstr, sizeof (errorstr),
426361f55a5SMarcel Telka t_errno, errno);
4277c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
428361f55a5SMarcel Telka "svc_tli_create: could not bind: %s",
429361f55a5SMarcel Telka errorstr);
4307c478bd9Sstevel@tonic-gate goto freedata;
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
434*dec98d2aSGordon Ross /*
435*dec98d2aSGordon Ross * If requested, set SO_EXCLBIND on each binding.
436*dec98d2aSGordon Ross *
437*dec98d2aSGordon Ross * SO_EXCLBIND has the following properties
438*dec98d2aSGordon Ross * - an fd bound to port P via IPv4 will prevent an IPv6
439*dec98d2aSGordon Ross * bind to port P (and vice versa)
440*dec98d2aSGordon Ross * - an fd bound to a wildcard IP address for port P will
441*dec98d2aSGordon Ross * prevent a more specific IP address bind to port P
442*dec98d2aSGordon Ross * (see {tcp,udp}.c for details)
443*dec98d2aSGordon Ross *
444*dec98d2aSGordon Ross * We use the latter property to prevent hijacking of RPC
445*dec98d2aSGordon Ross * services that reside at non-privileged ports.
446*dec98d2aSGordon Ross *
447*dec98d2aSGordon Ross * When the bind address is not specified, each bind gets a
448*dec98d2aSGordon Ross * new port number, and (for IP transports) we should set
449*dec98d2aSGordon Ross * the exclusive flag after every IP bind. That's the
450*dec98d2aSGordon Ross * strcmp nc_proto part of the expression below.
451*dec98d2aSGordon Ross *
452*dec98d2aSGordon Ross * When the bind address IS specified, we need to set the
453*dec98d2aSGordon Ross * exclusive flag only after we've bound both IPv6+IPv4,
454*dec98d2aSGordon Ross * or the IPv4 bind will fail. Setting the exclusive flag
455*dec98d2aSGordon Ross * after the "tcp" or "udp" transport bind does that.
456*dec98d2aSGordon Ross * That's the strcmp nc_netid part below.
457*dec98d2aSGordon Ross */
458*dec98d2aSGordon Ross if (nconf != NULL && ((bindaddr == NULL &&
459*dec98d2aSGordon Ross (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
460*dec98d2aSGordon Ross strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
461*dec98d2aSGordon Ross (strcmp(nconf->nc_netid, "tcp") == 0 ||
462*dec98d2aSGordon Ross strcmp(nconf->nc_netid, "udp") == 0))) {
463*dec98d2aSGordon Ross bool_t exclbind = FALSE;
464*dec98d2aSGordon Ross (void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind);
465*dec98d2aSGordon Ross if (exclbind &&
466*dec98d2aSGordon Ross __rpc_tli_set_options(fd, SOL_SOCKET,
467*dec98d2aSGordon Ross SO_EXCLBIND, 1) < 0) {
468*dec98d2aSGordon Ross syslog(LOG_ERR,
469*dec98d2aSGordon Ross "svc_tli_create: can't set EXCLBIND [netid='%s']",
470*dec98d2aSGordon Ross nconf->nc_netid);
471*dec98d2aSGordon Ross goto freedata;
472*dec98d2aSGordon Ross }
473*dec98d2aSGordon Ross }
474*dec98d2aSGordon Ross
4757c478bd9Sstevel@tonic-gate /* Enable options of returning the ip's for udp */
4767c478bd9Sstevel@tonic-gate if (nconf) {
477361f55a5SMarcel Telka int ret = 0;
478361f55a5SMarcel Telka if (strcmp(nconf->nc_netid, "udp6") == 0) {
479361f55a5SMarcel Telka ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
480361f55a5SMarcel Telka IPV6_RECVPKTINFO, 1);
481361f55a5SMarcel Telka if (ret < 0) {
482361f55a5SMarcel Telka char errorstr[100];
483361f55a5SMarcel Telka
484361f55a5SMarcel Telka __tli_sys_strerror(errorstr,
485361f55a5SMarcel Telka sizeof (errorstr), t_errno, errno);
486361f55a5SMarcel Telka (void) syslog(LOG_ERR,
487361f55a5SMarcel Telka "svc_tli_create: "
488361f55a5SMarcel Telka "IPV6_RECVPKTINFO(2): %s",
489361f55a5SMarcel Telka errorstr);
490361f55a5SMarcel Telka goto freedata;
491361f55a5SMarcel Telka }
492361f55a5SMarcel Telka } else if (strcmp(nconf->nc_netid, "udp") == 0) {
493361f55a5SMarcel Telka ret = __rpc_tli_set_options(fd, IPPROTO_IP,
494361f55a5SMarcel Telka IP_RECVDSTADDR, 1);
495361f55a5SMarcel Telka if (ret < 0) {
496361f55a5SMarcel Telka char errorstr[100];
497361f55a5SMarcel Telka
498361f55a5SMarcel Telka __tli_sys_strerror(errorstr,
499361f55a5SMarcel Telka sizeof (errorstr), t_errno, errno);
500361f55a5SMarcel Telka (void) syslog(LOG_ERR,
501361f55a5SMarcel Telka "svc_tli_create: "
502361f55a5SMarcel Telka "IP_RECVDSTADDR(2): %s", errorstr);
503361f55a5SMarcel Telka goto freedata;
504361f55a5SMarcel Telka }
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate break;
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate case T_IDLE:
5107c478bd9Sstevel@tonic-gate if (bindaddr) {
5117c478bd9Sstevel@tonic-gate /* Copy the entire stuff in tres */
5127c478bd9Sstevel@tonic-gate if (tres->addr.maxlen < bindaddr->addr.len) {
5137c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
5147c478bd9Sstevel@tonic-gate "svc_tli_create: illegal netbuf length");
5157c478bd9Sstevel@tonic-gate goto freedata;
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate tres->addr.len = bindaddr->addr.len;
5187c478bd9Sstevel@tonic-gate (void) memcpy(tres->addr.buf, bindaddr->addr.buf,
519361f55a5SMarcel Telka (int)tres->addr.len);
5207c478bd9Sstevel@tonic-gate } else
5217c478bd9Sstevel@tonic-gate if (t_getname(fd, &(tres->addr), LOCALNAME) == -1)
5227c478bd9Sstevel@tonic-gate tres->addr.len = 0;
5237c478bd9Sstevel@tonic-gate break;
5247c478bd9Sstevel@tonic-gate case T_INREL:
5257c478bd9Sstevel@tonic-gate (void) t_rcvrel(fd);
5267c478bd9Sstevel@tonic-gate (void) t_sndrel(fd);
527361f55a5SMarcel Telka (void) syslog(LOG_ERR, "svc_tli_create: other side wants to "
528361f55a5SMarcel Telka "release connection");
5297c478bd9Sstevel@tonic-gate goto freedata;
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate case T_INCON:
5327c478bd9Sstevel@tonic-gate /* Do nothing here. Assume this is handled in rendezvous */
5337c478bd9Sstevel@tonic-gate break;
5347c478bd9Sstevel@tonic-gate case T_DATAXFER:
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate * This takes care of the case where a fd
5377c478bd9Sstevel@tonic-gate * is passed on which a connection has already
5387c478bd9Sstevel@tonic-gate * been accepted.
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate if (t_getname(fd, &(tres->addr), LOCALNAME) == -1)
5417c478bd9Sstevel@tonic-gate tres->addr.len = 0;
5427c478bd9Sstevel@tonic-gate break;
5437c478bd9Sstevel@tonic-gate default:
5447c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
5457c478bd9Sstevel@tonic-gate "svc_tli_create: connection in a wierd state (%d)", state);
5467c478bd9Sstevel@tonic-gate goto freedata;
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate /*
5507c478bd9Sstevel@tonic-gate * call transport specific function.
5517c478bd9Sstevel@tonic-gate */
5527c478bd9Sstevel@tonic-gate switch (tinfo.servtype) {
5537c478bd9Sstevel@tonic-gate case T_COTS_ORD:
5547c478bd9Sstevel@tonic-gate case T_COTS:
5557c478bd9Sstevel@tonic-gate if (state == T_DATAXFER)
5567c478bd9Sstevel@tonic-gate xprt = svc_fd_create_private(fd, sendsz,
557361f55a5SMarcel Telka recvsz);
5587c478bd9Sstevel@tonic-gate else
5597c478bd9Sstevel@tonic-gate xprt = svc_vc_create_private(fd, sendsz,
560361f55a5SMarcel Telka recvsz);
5617c478bd9Sstevel@tonic-gate if (!nconf || !xprt)
5627c478bd9Sstevel@tonic-gate break;
5637c478bd9Sstevel@tonic-gate if ((tinfo.servtype == T_COTS_ORD) &&
564361f55a5SMarcel Telka (state != T_DATAXFER) &&
565361f55a5SMarcel Telka (strcmp(nconf->nc_protofmly, "inet") == 0))
5667c478bd9Sstevel@tonic-gate (void) __svc_vc_setflag(xprt, TRUE);
5677c478bd9Sstevel@tonic-gate break;
5687c478bd9Sstevel@tonic-gate case T_CLTS:
5697c478bd9Sstevel@tonic-gate xprt = svc_dg_create_private(fd, sendsz, recvsz);
5707c478bd9Sstevel@tonic-gate break;
5717c478bd9Sstevel@tonic-gate default:
5727c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR,
5737c478bd9Sstevel@tonic-gate "svc_tli_create: bad service type");
5747c478bd9Sstevel@tonic-gate goto freedata;
5757c478bd9Sstevel@tonic-gate }
57661961e0fSrobinson if (xprt == NULL)
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate * The error messages here are spitted out by the lower layers:
5797c478bd9Sstevel@tonic-gate * svc_vc_create(), svc_fd_create() and svc_dg_create().
5807c478bd9Sstevel@tonic-gate */
5817c478bd9Sstevel@tonic-gate goto freedata;
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate /* fill in the other xprt information */
5847c478bd9Sstevel@tonic-gate
5857c478bd9Sstevel@tonic-gate /* Assign the local bind address */
5867c478bd9Sstevel@tonic-gate xprt->xp_ltaddr = tres->addr;
5877c478bd9Sstevel@tonic-gate /* Fill in type of service */
5887c478bd9Sstevel@tonic-gate xprt->xp_type = tinfo.servtype;
5897c478bd9Sstevel@tonic-gate tres->addr.buf = NULL;
5907c478bd9Sstevel@tonic-gate (void) t_free((char *)tres, T_BIND);
5917c478bd9Sstevel@tonic-gate tres = NULL;
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate xprt->xp_rtaddr.len = 0;
5947c478bd9Sstevel@tonic-gate xprt->xp_rtaddr.maxlen = __rpc_get_a_size(tinfo.addr);
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /* Allocate space for the remote bind info */
59761961e0fSrobinson if ((xprt->xp_rtaddr.buf = malloc(xprt->xp_rtaddr.maxlen)) == NULL) {
5987c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
5997c478bd9Sstevel@tonic-gate goto freedata;
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate if (nconf) {
6037c478bd9Sstevel@tonic-gate xprt->xp_netid = strdup(nconf->nc_netid);
6047c478bd9Sstevel@tonic-gate if (xprt->xp_netid == NULL) {
6057c478bd9Sstevel@tonic-gate if (xprt->xp_rtaddr.buf)
6067c478bd9Sstevel@tonic-gate free(xprt->xp_rtaddr.buf);
6077c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_tli_create: strdup failed!");
6087c478bd9Sstevel@tonic-gate goto freedata;
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate xprt->xp_tp = strdup(nconf->nc_device);
6117c478bd9Sstevel@tonic-gate if (xprt->xp_tp == NULL) {
6127c478bd9Sstevel@tonic-gate if (xprt->xp_rtaddr.buf)
6137c478bd9Sstevel@tonic-gate free(xprt->xp_rtaddr.buf);
6147c478bd9Sstevel@tonic-gate if (xprt->xp_netid)
6157c478bd9Sstevel@tonic-gate free(xprt->xp_netid);
6167c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "svc_tli_create: strdup failed!");
6177c478bd9Sstevel@tonic-gate goto freedata;
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate * if (madefd && (tinfo.servtype == T_CLTS))
62361961e0fSrobinson * (void) ioctl(fd, I_POP, NULL);
6247c478bd9Sstevel@tonic-gate */
6257c478bd9Sstevel@tonic-gate xprt_register(xprt);
6267c478bd9Sstevel@tonic-gate return (xprt);
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate freedata:
6297c478bd9Sstevel@tonic-gate if (madefd)
6307c478bd9Sstevel@tonic-gate (void) t_close(fd);
6317c478bd9Sstevel@tonic-gate if (tres)
6327c478bd9Sstevel@tonic-gate (void) t_free((char *)tres, T_BIND);
6337c478bd9Sstevel@tonic-gate if (xprt) {
6347c478bd9Sstevel@tonic-gate if (!madefd) /* so that svc_destroy doesnt close fd */
6357c478bd9Sstevel@tonic-gate xprt->xp_fd = RPC_ANYFD;
6367c478bd9Sstevel@tonic-gate SVC_DESTROY(xprt);
6377c478bd9Sstevel@tonic-gate }
63861961e0fSrobinson return (NULL);
6397c478bd9Sstevel@tonic-gate }
640