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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. 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
);
90 __svc_free_xprtlist(void)
92 __svc_free_xlist(&_svc_xprtlist
, &xprtlist_lock
);
96 svc_create(void (*dispatch
)(), const rpcprog_t prognum
, const rpcvers_t versnum
,
102 struct netconfig
*nconf
;
107 * Check if service should register over doors transport.
109 if (__rpc_try_doors(nettype
, &try_others
)) {
110 if (svc_door_create(dispatch
, prognum
, versnum
, 0) == NULL
)
111 (void) syslog(LOG_ERR
,
112 "svc_create: could not register over doors");
118 if ((handle
= __rpc_setconf((char *)nettype
)) == NULL
) {
119 (void) syslog(LOG_ERR
, "svc_create: unknown protocol");
122 while (nconf
= __rpc_getconf(handle
)) {
123 (void) mutex_lock(&xprtlist_lock
);
124 for (l
= _svc_xprtlist
; l
; l
= l
->next
) {
125 if (strcmp(l
->xprt
->xp_netid
, nconf
->nc_netid
) == 0) {
126 /* Found an old one, use it */
127 (void) rpcb_unset(prognum
, versnum
, nconf
);
128 if (svc_reg(l
->xprt
, prognum
, versnum
,
129 dispatch
, nconf
) == FALSE
)
130 (void) syslog(LOG_ERR
, "svc_create: "
131 "could not register prog %d vers "
133 prognum
, versnum
, nconf
->nc_netid
);
139 (void) mutex_unlock(&xprtlist_lock
);
141 /* It was not found. Now create a new one */
142 xprt
= svc_tp_create(dispatch
, prognum
, versnum
, nconf
);
144 if (!__svc_add_to_xlist(&_svc_xprtlist
, xprt
,
146 (void) syslog(LOG_ERR
,
147 "svc_create: no memory");
154 __rpc_endconf(handle
);
156 * In case of num == 0; the error messages are generated by the
157 * underlying layers; and hence not needed here.
163 * The high level interface to svc_tli_create().
164 * It tries to create a server for "nconf" and registers the service
165 * with the rpcbind. It calls svc_tli_create();
168 svc_tp_create(void (*dispatch
)(), const rpcprog_t prognum
,
169 const rpcvers_t versnum
, const struct netconfig
*nconf
)
174 (void) syslog(LOG_ERR
, "svc_tp_create: invalid netconfig "
175 "structure for prog %d vers %d", prognum
, versnum
);
179 xprt
= svc_tli_create_common(RPC_ANYFD
, nconf
, NULL
, 0, 0);
183 (void) rpcb_unset(prognum
, versnum
, (struct netconfig
*)nconf
);
184 if (svc_reg(xprt
, prognum
, versnum
, dispatch
, nconf
) == FALSE
) {
185 (void) syslog(LOG_ERR
,
186 "svc_tp_create: Could not register prog %d vers %d on %s",
187 prognum
, versnum
, nconf
->nc_netid
);
195 svc_tli_create(const int fd
, const struct netconfig
*nconf
,
196 const struct t_bind
*bindaddr
, const uint_t sendsz
, const uint_t recvsz
)
198 return (svc_tli_create_common(fd
, nconf
, bindaddr
, sendsz
, recvsz
));
202 * If fd is RPC_ANYFD, then it opens a fd for the given transport
203 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
204 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
205 * NULL bindadr and Connection oriented transports, the value of qlen
206 * is set arbitrarily.
208 * If sendsz or recvsz are zero, their default values are chosen.
211 svc_tli_create_common(const int ofd
, const struct netconfig
*nconf
,
212 const struct t_bind
*bindaddr
, const uint_t sendsz
,
215 SVCXPRT
*xprt
= NULL
; /* service handle */
216 struct t_info tinfo
; /* transport info */
217 struct t_bind
*tres
= NULL
; /* bind info */
218 bool_t madefd
= FALSE
; /* whether fd opened here */
219 int state
; /* state of the transport provider */
222 if (fd
== RPC_ANYFD
) {
224 (void) syslog(LOG_ERR
,
225 "svc_tli_create: invalid netconfig");
228 fd
= t_open(nconf
->nc_device
, O_RDWR
, &tinfo
);
232 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
234 (void) syslog(LOG_ERR
, "svc_tli_create: could not open "
235 "connection for %s: %s", nconf
->nc_netid
, errorstr
);
242 * It is an open descriptor. Sync it & get the transport info.
244 if ((state
= t_sync(fd
)) == -1) {
247 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
249 (void) syslog(LOG_ERR
,
250 "svc_tli_create: could not do t_sync: %s",
254 if (t_getinfo(fd
, &tinfo
) == -1) {
257 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
259 (void) syslog(LOG_ERR
, "svc_tli_create: could not get "
260 "transport information: %s", errorstr
);
263 /* Enable options of returning the ip's for udp */
266 if (strcmp(nconf
->nc_netid
, "udp6") == 0) {
267 ret
= __rpc_tli_set_options(fd
, IPPROTO_IPV6
,
268 IPV6_RECVPKTINFO
, 1);
272 __tli_sys_strerror(errorstr
,
273 sizeof (errorstr
), t_errno
, errno
);
274 (void) syslog(LOG_ERR
,
276 "IPV6_RECVPKTINFO(1): %s",
280 } else if (strcmp(nconf
->nc_netid
, "udp") == 0) {
281 ret
= __rpc_tli_set_options(fd
, IPPROTO_IP
,
286 __tli_sys_strerror(errorstr
,
287 sizeof (errorstr
), t_errno
, errno
);
288 (void) syslog(LOG_ERR
,
290 "IP_RECVDSTADDR(1): %s", errorstr
);
298 * If the fd is unbound, try to bind it.
299 * In any case, try to get its bound info in tres
301 /* LINTED pointer alignment */
302 tres
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
304 (void) syslog(LOG_ERR
, "svc_tli_create: No memory!");
309 bool_t tcp
, exclbind
;
312 * SO_EXCLBIND has the following properties
313 * - an fd bound to port P via IPv4 will prevent an IPv6
314 * bind to port P (and vice versa)
315 * - an fd bound to a wildcard IP address for port P will
316 * prevent a more specific IP address bind to port P
317 * (see {tcp,udp}.c for details)
319 * We use the latter property to prevent hijacking of RPC
320 * services that reside at non-privileged ports.
322 tcp
= nconf
? (strcmp(nconf
->nc_proto
, NC_TCP
) == 0) : 0;
324 (tcp
|| (strcmp(nconf
->nc_proto
, NC_UDP
) == 0)) &&
325 rpc_control(__RPC_SVC_EXCLBIND_GET
, &exclbind
)) {
327 if (__rpc_tli_set_options(fd
, SOL_SOCKET
,
328 SO_EXCLBIND
, 1) < 0) {
330 "svc_tli_create: can't set EXCLBIND [netid='%s']",
337 if (t_bind(fd
, (struct t_bind
*)bindaddr
, tres
) == -1) {
340 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
342 (void) syslog(LOG_ERR
,
343 "svc_tli_create: could not bind: %s",
348 * Should compare the addresses only if addr.len
351 if (bindaddr
->addr
.len
&&
352 (memcmp(bindaddr
->addr
.buf
, tres
->addr
.buf
,
353 (int)tres
->addr
.len
) != 0)) {
354 (void) syslog(LOG_ERR
, "svc_tli_create: could "
355 "not bind to requested address: address "
360 if (rpc_control(__RPC_SVC_LSTNBKLOG_GET
, &tres
->qlen
)
363 "svc_tli_create: can't get listen backlog");
367 if (t_bind(fd
, tres
, tres
) == -1) {
370 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
372 (void) syslog(LOG_ERR
,
373 "svc_tli_create: could not bind: %s",
379 /* Enable options of returning the ip's for udp */
382 if (strcmp(nconf
->nc_netid
, "udp6") == 0) {
383 ret
= __rpc_tli_set_options(fd
, IPPROTO_IPV6
,
384 IPV6_RECVPKTINFO
, 1);
388 __tli_sys_strerror(errorstr
,
389 sizeof (errorstr
), t_errno
, errno
);
390 (void) syslog(LOG_ERR
,
392 "IPV6_RECVPKTINFO(2): %s",
396 } else if (strcmp(nconf
->nc_netid
, "udp") == 0) {
397 ret
= __rpc_tli_set_options(fd
, IPPROTO_IP
,
402 __tli_sys_strerror(errorstr
,
403 sizeof (errorstr
), t_errno
, errno
);
404 (void) syslog(LOG_ERR
,
406 "IP_RECVDSTADDR(2): %s", errorstr
);
415 /* Copy the entire stuff in tres */
416 if (tres
->addr
.maxlen
< bindaddr
->addr
.len
) {
417 (void) syslog(LOG_ERR
,
418 "svc_tli_create: illegal netbuf length");
421 tres
->addr
.len
= bindaddr
->addr
.len
;
422 (void) memcpy(tres
->addr
.buf
, bindaddr
->addr
.buf
,
423 (int)tres
->addr
.len
);
425 if (t_getname(fd
, &(tres
->addr
), LOCALNAME
) == -1)
431 (void) syslog(LOG_ERR
, "svc_tli_create: other side wants to "
432 "release connection");
436 /* Do nothing here. Assume this is handled in rendezvous */
440 * This takes care of the case where a fd
441 * is passed on which a connection has already
444 if (t_getname(fd
, &(tres
->addr
), LOCALNAME
) == -1)
448 (void) syslog(LOG_ERR
,
449 "svc_tli_create: connection in a wierd state (%d)", state
);
454 * call transport specific function.
456 switch (tinfo
.servtype
) {
459 if (state
== T_DATAXFER
)
460 xprt
= svc_fd_create_private(fd
, sendsz
,
463 xprt
= svc_vc_create_private(fd
, sendsz
,
467 if ((tinfo
.servtype
== T_COTS_ORD
) &&
468 (state
!= T_DATAXFER
) &&
469 (strcmp(nconf
->nc_protofmly
, "inet") == 0))
470 (void) __svc_vc_setflag(xprt
, TRUE
);
473 xprt
= svc_dg_create_private(fd
, sendsz
, recvsz
);
476 (void) syslog(LOG_ERR
,
477 "svc_tli_create: bad service type");
482 * The error messages here are spitted out by the lower layers:
483 * svc_vc_create(), svc_fd_create() and svc_dg_create().
487 /* fill in the other xprt information */
489 /* Assign the local bind address */
490 xprt
->xp_ltaddr
= tres
->addr
;
491 /* Fill in type of service */
492 xprt
->xp_type
= tinfo
.servtype
;
493 tres
->addr
.buf
= NULL
;
494 (void) t_free((char *)tres
, T_BIND
);
497 xprt
->xp_rtaddr
.len
= 0;
498 xprt
->xp_rtaddr
.maxlen
= __rpc_get_a_size(tinfo
.addr
);
500 /* Allocate space for the remote bind info */
501 if ((xprt
->xp_rtaddr
.buf
= malloc(xprt
->xp_rtaddr
.maxlen
)) == NULL
) {
502 (void) syslog(LOG_ERR
, "svc_tli_create: No memory!");
507 xprt
->xp_netid
= strdup(nconf
->nc_netid
);
508 if (xprt
->xp_netid
== NULL
) {
509 free(xprt
->xp_rtaddr
.buf
);
510 syslog(LOG_ERR
, "svc_tli_create: strdup failed!");
513 xprt
->xp_tp
= strdup(nconf
->nc_device
);
514 if (xprt
->xp_tp
== NULL
) {
515 free(xprt
->xp_rtaddr
.buf
);
516 free(xprt
->xp_netid
);
517 syslog(LOG_ERR
, "svc_tli_create: strdup failed!");
523 * if (madefd && (tinfo.servtype == T_CLTS))
524 * (void) ioctl(fd, I_POP, NULL);
533 (void) t_free((char *)tres
, T_BIND
);
535 if (!madefd
) /* so that svc_destroy doesnt close fd */
536 xprt
->xp_fd
= RPC_ANYFD
;