4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
31 * svc_generic.c, Server side for RPC.
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <netinet/udp.h>
45 #include <sys/types.h>
48 #include <rpc/nettype.h>
53 #include <nfs/nfs_acl.h>
54 #include <rpcsvc/mount.h>
55 #include <rpcsvc/nsm_addr.h>
56 #include <rpcsvc/rquota.h>
57 #include <rpcsvc/sm_inter.h>
58 #include <rpcsvc/nlm_prot.h>
60 extern int __svc_vc_setflag(SVCXPRT
*, int);
62 extern SVCXPRT
*svc_dg_create_private(int, uint_t
, uint_t
);
63 extern SVCXPRT
*svc_vc_create_private(int, uint_t
, uint_t
);
64 extern SVCXPRT
*svc_fd_create_private(int, uint_t
, uint_t
);
66 extern bool_t
__svc_add_to_xlist(SVCXPRT_LIST
**, SVCXPRT
*, mutex_t
*);
67 extern void __svc_free_xlist(SVCXPRT_LIST
**, mutex_t
*);
69 extern bool_t
__rpc_try_doors(const char *, bool_t
*);
72 * The highest level interface for server creation.
73 * It tries for all the nettokens in that particular class of token
74 * and returns the number of handles it can create and/or find.
76 * It creates a link list of all the handles it could create.
77 * If svc_create() is called multiple times, it uses the handle
78 * created earlier instead of creating a new handle every time.
81 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
83 SVCXPRT_LIST
*_svc_xprtlist
= NULL
;
84 extern mutex_t xprtlist_lock
;
86 static SVCXPRT
* svc_tli_create_common(int, const struct netconfig
*,
87 const struct t_bind
*, uint_t
, uint_t
);
89 static SVCXPRT
*svc_tp_create_bind(void (*dispatch
)(),
90 const rpcprog_t
, const rpcvers_t
,
91 const struct netconfig
*, const struct t_bind
*);
94 __svc_free_xprtlist(void)
96 __svc_free_xlist(&_svc_xprtlist
, &xprtlist_lock
);
100 svc_create(void (*dispatch
)(), const rpcprog_t prognum
, const rpcvers_t versnum
,
106 struct netconfig
*nconf
;
111 * Check if service should register over doors transport.
113 if (__rpc_try_doors(nettype
, &try_others
)) {
114 if (svc_door_create(dispatch
, prognum
, versnum
, 0) == NULL
)
115 (void) syslog(LOG_ERR
,
116 "svc_create: could not register over doors");
122 if ((handle
= __rpc_setconf((char *)nettype
)) == NULL
) {
123 (void) syslog(LOG_ERR
, "svc_create: unknown protocol");
126 while (nconf
= __rpc_getconf(handle
)) {
127 (void) mutex_lock(&xprtlist_lock
);
128 for (l
= _svc_xprtlist
; l
; l
= l
->next
) {
129 if (strcmp(l
->xprt
->xp_netid
, nconf
->nc_netid
) == 0) {
130 /* Found an old one, use it */
131 (void) rpcb_unset(prognum
, versnum
, nconf
);
132 if (svc_reg(l
->xprt
, prognum
, versnum
,
133 dispatch
, nconf
) == FALSE
)
134 (void) syslog(LOG_ERR
, "svc_create: "
135 "could not register prog %d vers "
137 prognum
, versnum
, nconf
->nc_netid
);
143 (void) mutex_unlock(&xprtlist_lock
);
145 /* It was not found. Now create a new one */
146 xprt
= svc_tp_create(dispatch
, prognum
, versnum
, nconf
);
148 if (!__svc_add_to_xlist(&_svc_xprtlist
, xprt
,
150 (void) syslog(LOG_ERR
,
151 "svc_create: no memory");
158 __rpc_endconf(handle
);
160 * In case of num == 0; the error messages are generated by the
161 * underlying layers; and hence not needed here.
167 * The high level interface to svc_tli_create().
168 * It tries to create a server for "nconf" and registers the service
172 svc_tp_create(void (*dispatch
)(), const rpcprog_t prognum
,
173 const rpcvers_t versnum
, const struct netconfig
*nconf
)
175 return (svc_tp_create_bind(dispatch
, prognum
, versnum
, nconf
, NULL
));
179 * svc_tp_create_addr()
180 * Variant of svc_tp_create() that allows specifying just the
181 * the binding address, for convenience.
184 svc_tp_create_addr(void (*dispatch
)(), const rpcprog_t prognum
,
185 const rpcvers_t versnum
, const struct netconfig
*nconf
,
186 const struct netbuf
*addr
)
189 struct t_bind
*bindp
= NULL
;
194 if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET
, &bind
.qlen
)) {
196 "svc_tp_create: can't get listen backlog");
203 * When bindp == NULL, this is the same as svc_tp_create().
205 return (svc_tp_create_bind(dispatch
, prognum
, versnum
,
210 svc_tp_create_bind(void (*dispatch
)(), const rpcprog_t prognum
,
211 const rpcvers_t versnum
, const struct netconfig
*nconf
,
212 const struct t_bind
*bindaddr
)
217 (void) syslog(LOG_ERR
, "svc_tp_create: invalid netconfig "
218 "structure for prog %d vers %d", prognum
, versnum
);
222 xprt
= svc_tli_create_common(RPC_ANYFD
, nconf
, bindaddr
, 0, 0);
226 (void) rpcb_unset(prognum
, versnum
, (struct netconfig
*)nconf
);
227 if (svc_reg(xprt
, prognum
, versnum
, dispatch
, nconf
) == FALSE
) {
228 (void) syslog(LOG_ERR
,
229 "svc_tp_create: Could not register prog %d vers %d on %s",
230 prognum
, versnum
, nconf
->nc_netid
);
238 svc_tli_create(const int fd
, const struct netconfig
*nconf
,
239 const struct t_bind
*bindaddr
, const uint_t sendsz
, const uint_t recvsz
)
241 return (svc_tli_create_common(fd
, nconf
, bindaddr
, sendsz
, recvsz
));
245 * If fd is RPC_ANYFD, then it opens a fd for the given transport
246 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
247 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
248 * NULL bindadr and Connection oriented transports, the value of qlen
249 * is set arbitrarily.
251 * If sendsz or recvsz are zero, their default values are chosen.
254 svc_tli_create_common(const int ofd
, const struct netconfig
*nconf
,
255 const struct t_bind
*bindaddr
, const uint_t sendsz
,
258 SVCXPRT
*xprt
= NULL
; /* service handle */
259 struct t_info tinfo
; /* transport info */
260 struct t_bind
*tres
= NULL
; /* bind info */
261 bool_t madefd
= FALSE
; /* whether fd opened here */
262 int state
; /* state of the transport provider */
265 if (fd
== RPC_ANYFD
) {
267 (void) syslog(LOG_ERR
,
268 "svc_tli_create: invalid netconfig");
271 fd
= t_open(nconf
->nc_device
, O_RDWR
, &tinfo
);
275 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
277 (void) syslog(LOG_ERR
, "svc_tli_create: could not open "
278 "connection for %s: %s", nconf
->nc_netid
, errorstr
);
285 * It is an open descriptor. Sync it & get the transport info.
287 if ((state
= t_sync(fd
)) == -1) {
290 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
292 (void) syslog(LOG_ERR
,
293 "svc_tli_create: could not do t_sync: %s",
297 if (t_getinfo(fd
, &tinfo
) == -1) {
300 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
302 (void) syslog(LOG_ERR
, "svc_tli_create: could not get "
303 "transport information: %s", errorstr
);
306 /* Enable options of returning the ip's for udp */
309 if (strcmp(nconf
->nc_netid
, "udp6") == 0) {
310 ret
= __rpc_tli_set_options(fd
, IPPROTO_IPV6
,
311 IPV6_RECVPKTINFO
, 1);
315 __tli_sys_strerror(errorstr
,
316 sizeof (errorstr
), t_errno
, errno
);
317 (void) syslog(LOG_ERR
,
319 "IPV6_RECVPKTINFO(1): %s",
323 } else if (strcmp(nconf
->nc_netid
, "udp") == 0) {
324 ret
= __rpc_tli_set_options(fd
, IPPROTO_IP
,
329 __tli_sys_strerror(errorstr
,
330 sizeof (errorstr
), t_errno
, errno
);
331 (void) syslog(LOG_ERR
,
333 "IP_RECVDSTADDR(1): %s", errorstr
);
341 * If the fd is unbound, try to bind it.
342 * In any case, try to get its bound info in tres
344 /* LINTED pointer alignment */
345 tres
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
347 (void) syslog(LOG_ERR
, "svc_tli_create: No memory!");
355 * Services that specify a bind address typically
356 * use a fixed service (IP port) so we need to set
357 * SO_REUSEADDR to prevent bind errors on restart.
359 if (bindaddr
->addr
.len
!= 0)
360 (void) __rpc_tli_set_options(fd
, SOL_SOCKET
,
362 if (t_bind(fd
, (struct t_bind
*)bindaddr
, tres
) == -1) {
365 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
367 (void) syslog(LOG_ERR
,
368 "svc_tli_create: could not bind: %s",
373 * Should compare the addresses only if addr.len
376 if (bindaddr
->addr
.len
&&
377 (memcmp(bindaddr
->addr
.buf
, tres
->addr
.buf
,
378 (int)tres
->addr
.len
) != 0)) {
379 (void) syslog(LOG_ERR
, "svc_tli_create: could "
380 "not bind to requested address: address "
385 if (rpc_control(__RPC_SVC_LSTNBKLOG_GET
, &tres
->qlen
)
388 "svc_tli_create: can't get listen backlog");
392 if (t_bind(fd
, tres
, tres
) == -1) {
395 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
397 (void) syslog(LOG_ERR
,
398 "svc_tli_create: could not bind: %s",
405 * If requested, set SO_EXCLBIND on each binding.
407 * SO_EXCLBIND has the following properties
408 * - an fd bound to port P via IPv4 will prevent an IPv6
409 * bind to port P (and vice versa)
410 * - an fd bound to a wildcard IP address for port P will
411 * prevent a more specific IP address bind to port P
412 * (see {tcp,udp}.c for details)
414 * We use the latter property to prevent hijacking of RPC
415 * services that reside at non-privileged ports.
417 * When the bind address is not specified, each bind gets a
418 * new port number, and (for IP transports) we should set
419 * the exclusive flag after every IP bind. That's the
420 * strcmp nc_proto part of the expression below.
422 * When the bind address IS specified, we need to set the
423 * exclusive flag only after we've bound both IPv6+IPv4,
424 * or the IPv4 bind will fail. Setting the exclusive flag
425 * after the "tcp" or "udp" transport bind does that.
426 * That's the strcmp nc_netid part below.
428 if (nconf
!= NULL
&& ((bindaddr
== NULL
&&
429 (strcmp(nconf
->nc_proto
, NC_TCP
) == 0 ||
430 strcmp(nconf
->nc_proto
, NC_UDP
) == 0)) ||
431 (strcmp(nconf
->nc_netid
, "tcp") == 0 ||
432 strcmp(nconf
->nc_netid
, "udp") == 0))) {
433 bool_t exclbind
= FALSE
;
434 (void) rpc_control(__RPC_SVC_EXCLBIND_GET
, &exclbind
);
436 __rpc_tli_set_options(fd
, SOL_SOCKET
,
437 SO_EXCLBIND
, 1) < 0) {
439 "svc_tli_create: can't set EXCLBIND [netid='%s']",
445 /* Enable options of returning the ip's for udp */
448 if (strcmp(nconf
->nc_netid
, "udp6") == 0) {
449 ret
= __rpc_tli_set_options(fd
, IPPROTO_IPV6
,
450 IPV6_RECVPKTINFO
, 1);
454 __tli_sys_strerror(errorstr
,
455 sizeof (errorstr
), t_errno
, errno
);
456 (void) syslog(LOG_ERR
,
458 "IPV6_RECVPKTINFO(2): %s",
462 } else if (strcmp(nconf
->nc_netid
, "udp") == 0) {
463 ret
= __rpc_tli_set_options(fd
, IPPROTO_IP
,
468 __tli_sys_strerror(errorstr
,
469 sizeof (errorstr
), t_errno
, errno
);
470 (void) syslog(LOG_ERR
,
472 "IP_RECVDSTADDR(2): %s", errorstr
);
481 /* Copy the entire stuff in tres */
482 if (tres
->addr
.maxlen
< bindaddr
->addr
.len
) {
483 (void) syslog(LOG_ERR
,
484 "svc_tli_create: illegal netbuf length");
487 tres
->addr
.len
= bindaddr
->addr
.len
;
488 (void) memcpy(tres
->addr
.buf
, bindaddr
->addr
.buf
,
489 (int)tres
->addr
.len
);
491 if (t_getname(fd
, &(tres
->addr
), LOCALNAME
) == -1)
497 (void) syslog(LOG_ERR
, "svc_tli_create: other side wants to "
498 "release connection");
502 /* Do nothing here. Assume this is handled in rendezvous */
506 * This takes care of the case where a fd
507 * is passed on which a connection has already
510 if (t_getname(fd
, &(tres
->addr
), LOCALNAME
) == -1)
514 (void) syslog(LOG_ERR
,
515 "svc_tli_create: connection in a wierd state (%d)", state
);
520 * call transport specific function.
522 switch (tinfo
.servtype
) {
525 if (state
== T_DATAXFER
)
526 xprt
= svc_fd_create_private(fd
, sendsz
,
529 xprt
= svc_vc_create_private(fd
, sendsz
,
533 if ((tinfo
.servtype
== T_COTS_ORD
) &&
534 (state
!= T_DATAXFER
) &&
535 (strcmp(nconf
->nc_protofmly
, "inet") == 0))
536 (void) __svc_vc_setflag(xprt
, TRUE
);
539 xprt
= svc_dg_create_private(fd
, sendsz
, recvsz
);
542 (void) syslog(LOG_ERR
,
543 "svc_tli_create: bad service type");
548 * The error messages here are spitted out by the lower layers:
549 * svc_vc_create(), svc_fd_create() and svc_dg_create().
553 /* fill in the other xprt information */
555 /* Assign the local bind address */
556 xprt
->xp_ltaddr
= tres
->addr
;
557 /* Fill in type of service */
558 xprt
->xp_type
= tinfo
.servtype
;
559 tres
->addr
.buf
= NULL
;
560 (void) t_free((char *)tres
, T_BIND
);
563 xprt
->xp_rtaddr
.len
= 0;
564 xprt
->xp_rtaddr
.maxlen
= __rpc_get_a_size(tinfo
.addr
);
566 /* Allocate space for the remote bind info */
567 if ((xprt
->xp_rtaddr
.buf
= malloc(xprt
->xp_rtaddr
.maxlen
)) == NULL
) {
568 (void) syslog(LOG_ERR
, "svc_tli_create: No memory!");
573 xprt
->xp_netid
= strdup(nconf
->nc_netid
);
574 if (xprt
->xp_netid
== NULL
) {
575 free(xprt
->xp_rtaddr
.buf
);
576 syslog(LOG_ERR
, "svc_tli_create: strdup failed!");
579 xprt
->xp_tp
= strdup(nconf
->nc_device
);
580 if (xprt
->xp_tp
== NULL
) {
581 free(xprt
->xp_rtaddr
.buf
);
582 free(xprt
->xp_netid
);
583 syslog(LOG_ERR
, "svc_tli_create: strdup failed!");
589 * if (madefd && (tinfo.servtype == T_CLTS))
590 * (void) ioctl(fd, I_POP, NULL);
599 (void) t_free((char *)tres
, T_BIND
);
601 if (!madefd
) /* so that svc_destroy doesnt close fd */
602 xprt
->xp_fd
= RPC_ANYFD
;