1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
25 */
26
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * svc_generic.c, Server side for RPC.
32 *
33 */
34
35 #include "mt.h"
36 #include <stdlib.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <netinet/udp.h>
41 #include <inttypes.h>
42 #include "rpc_mt.h"
43 #include <stdio.h>
44 #include <rpc/rpc.h>
45 #include <sys/types.h>
46 #include <errno.h>
47 #include <syslog.h>
48 #include <rpc/nettype.h>
49 #include <malloc.h>
50 #include <string.h>
51 #include <stropts.h>
52 #include <tsol/label.h>
53 #include <nfs/nfs.h>
54 #include <nfs/nfs_acl.h>
55 #include <rpcsvc/mount.h>
56 #include <rpcsvc/nsm_addr.h>
57 #include <rpcsvc/rquota.h>
58 #include <rpcsvc/sm_inter.h>
59 #include <rpcsvc/nlm_prot.h>
60
61 extern int __svc_vc_setflag(SVCXPRT *, int);
62
63 extern SVCXPRT *svc_dg_create_private(int, uint_t, uint_t);
64 extern SVCXPRT *svc_vc_create_private(int, uint_t, uint_t);
65 extern SVCXPRT *svc_fd_create_private(int, uint_t, uint_t);
66
67 extern bool_t __svc_add_to_xlist(SVCXPRT_LIST **, SVCXPRT *, mutex_t *);
68 extern void __svc_free_xlist(SVCXPRT_LIST **, mutex_t *);
69
70 extern bool_t __rpc_try_doors(const char *, bool_t *);
71
72 /*
73 * The highest level interface for server creation.
74 * It tries for all the nettokens in that particular class of token
75 * and returns the number of handles it can create and/or find.
76 *
77 * It creates a link list of all the handles it could create.
78 * If svc_create() is called multiple times, it uses the handle
79 * created earlier instead of creating a new handle every time.
80 */
81
82 /* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
83
84 SVCXPRT_LIST *_svc_xprtlist = NULL;
85 extern mutex_t xprtlist_lock;
86
87 static SVCXPRT * svc_tli_create_common(int, const struct netconfig *,
88 const struct t_bind *, uint_t, uint_t, boolean_t);
89
90 static SVCXPRT *svc_tp_create_bind(void (*dispatch)(),
91 const rpcprog_t, const rpcvers_t,
92 const struct netconfig *, const struct t_bind *);
93
94 boolean_t
is_multilevel(rpcprog_t prognum)95 is_multilevel(rpcprog_t prognum)
96 {
97 /* This is a list of identified multilevel service provider */
98 if ((prognum == MOUNTPROG) || (prognum == NFS_PROGRAM) ||
99 (prognum == NFS_ACL_PROGRAM) || (prognum == NLM_PROG) ||
100 (prognum == NSM_ADDR_PROGRAM) || (prognum == RQUOTAPROG) ||
101 (prognum == SM_PROG))
102 return (B_TRUE);
103
104 return (B_FALSE);
105 }
106
107 void
__svc_free_xprtlist(void)108 __svc_free_xprtlist(void)
109 {
110 __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock);
111 }
112
113 int
svc_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const char * nettype)114 svc_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum,
115 const char *nettype)
116 {
117 SVCXPRT_LIST *l;
118 int num = 0;
119 SVCXPRT *xprt;
120 struct netconfig *nconf;
121 void *handle;
122 bool_t try_others;
123
124 /*
125 * Check if service should register over doors transport.
126 */
127 if (__rpc_try_doors(nettype, &try_others)) {
128 if (svc_door_create(dispatch, prognum, versnum, 0) == NULL)
129 (void) syslog(LOG_ERR,
130 "svc_create: could not register over doors");
131 else
132 num++;
133 }
134 if (!try_others)
135 return (num);
136 if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
137 (void) syslog(LOG_ERR, "svc_create: unknown protocol");
138 return (0);
139 }
140 while (nconf = __rpc_getconf(handle)) {
141 (void) mutex_lock(&xprtlist_lock);
142 for (l = _svc_xprtlist; l; l = l->next) {
143 if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
144 /* Found an old one, use it */
145 (void) rpcb_unset(prognum, versnum, nconf);
146 if (svc_reg(l->xprt, prognum, versnum,
147 dispatch, nconf) == FALSE)
148 (void) syslog(LOG_ERR, "svc_create: "
149 "could not register prog %d vers "
150 "%d on %s",
151 prognum, versnum, nconf->nc_netid);
152 else
153 num++;
154 break;
155 }
156 }
157 (void) mutex_unlock(&xprtlist_lock);
158 if (l == NULL) {
159 /* It was not found. Now create a new one */
160 xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
161 if (xprt) {
162 if (!__svc_add_to_xlist(&_svc_xprtlist, xprt,
163 &xprtlist_lock)) {
164 (void) syslog(LOG_ERR,
165 "svc_create: no memory");
166 return (0);
167 }
168 num++;
169 }
170 }
171 }
172 __rpc_endconf(handle);
173 /*
174 * In case of num == 0; the error messages are generated by the
175 * underlying layers; and hence not needed here.
176 */
177 return (num);
178 }
179
180 /*
181 * The high level interface to svc_tli_create().
182 * It tries to create a server for "nconf" and registers the service
183 * with the rpcbind.
184 */
185 SVCXPRT *
svc_tp_create(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const struct netconfig * nconf)186 svc_tp_create(void (*dispatch)(), const rpcprog_t prognum,
187 const rpcvers_t versnum, const struct netconfig *nconf)
188 {
189 return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL));
190 }
191
192 /*
193 * svc_tp_create_addr()
194 * Variant of svc_tp_create() that allows specifying just the
195 * the binding address, for convenience.
196 */
197 SVCXPRT *
svc_tp_create_addr(void (* dispatch)(),const rpcprog_t prognum,const rpcvers_t versnum,const struct netconfig * nconf,const struct netbuf * addr)198 svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum,
199 const rpcvers_t versnum, const struct netconfig *nconf,
200 const struct netbuf *addr)
201 {
202 struct t_bind bind;
203 struct t_bind *bindp = NULL;
204
205 if (addr != NULL) {
206
207 bind.addr = *addr;
208 if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) {
209 syslog(LOG_ERR,
210 "svc_tp_create: can't get listen backlog");
211 return (NULL);
212 }
213 bindp = &bind;
214 }
215
216 /*
217 * When bindp == NULL, this is the same as svc_tp_create().
218 */
219 return (svc_tp_create_bind(dispatch, prognum, versnum,
220 nconf, bindp));
221 }
222
223 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 svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum,
225 const rpcvers_t versnum, const struct netconfig *nconf,
226 const struct t_bind *bindaddr)
227 {
228 SVCXPRT *xprt;
229 boolean_t anon_mlp = B_FALSE;
230
231 if (nconf == NULL) {
232 (void) syslog(LOG_ERR, "svc_tp_create: invalid netconfig "
233 "structure for prog %d vers %d", prognum, versnum);
234 return (NULL);
235 }
236
237 /* Some programs need to allocate MLP for multilevel services */
238 if (is_system_labeled() && is_multilevel(prognum))
239 anon_mlp = B_TRUE;
240 xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0,
241 anon_mlp);
242 if (xprt == NULL)
243 return (NULL);
244
245 (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf);
246 if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
247 (void) syslog(LOG_ERR,
248 "svc_tp_create: Could not register prog %d vers %d on %s",
249 prognum, versnum, nconf->nc_netid);
250 SVC_DESTROY(xprt);
251 return (NULL);
252 }
253 return (xprt);
254 }
255
256 SVCXPRT *
svc_tli_create(const int fd,const struct netconfig * nconf,const struct t_bind * bindaddr,const uint_t sendsz,const uint_t recvsz)257 svc_tli_create(const int fd, const struct netconfig *nconf,
258 const struct t_bind *bindaddr, const uint_t sendsz, const uint_t recvsz)
259 {
260 return (svc_tli_create_common(fd, nconf, bindaddr, sendsz, recvsz, 0));
261 }
262
263 /*
264 * If fd is RPC_ANYFD, then it opens a fd for the given transport
265 * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
266 * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
267 * NULL bindadr and Connection oriented transports, the value of qlen
268 * is set arbitrarily.
269 *
270 * If sendsz or recvsz are zero, their default values are chosen.
271 */
272 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)273 svc_tli_create_common(const int ofd, const struct netconfig *nconf,
274 const struct t_bind *bindaddr, const uint_t sendsz,
275 const uint_t recvsz, boolean_t mlp_flag)
276 {
277 SVCXPRT *xprt = NULL; /* service handle */
278 struct t_info tinfo; /* transport info */
279 struct t_bind *tres = NULL; /* bind info */
280 bool_t madefd = FALSE; /* whether fd opened here */
281 int state; /* state of the transport provider */
282 int fd = ofd;
283
284 if (fd == RPC_ANYFD) {
285 if (nconf == NULL) {
286 (void) syslog(LOG_ERR,
287 "svc_tli_create: invalid netconfig");
288 return (NULL);
289 }
290 fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
291 if (fd == -1) {
292 char errorstr[100];
293
294 __tli_sys_strerror(errorstr, sizeof (errorstr),
295 t_errno, errno);
296 (void) syslog(LOG_ERR, "svc_tli_create: could not open "
297 "connection for %s: %s", nconf->nc_netid, errorstr);
298 return (NULL);
299 }
300 madefd = TRUE;
301 state = T_UNBND;
302 } else {
303 /*
304 * It is an open descriptor. Sync it & get the transport info.
305 */
306 if ((state = t_sync(fd)) == -1) {
307 char errorstr[100];
308
309 __tli_sys_strerror(errorstr, sizeof (errorstr),
310 t_errno, errno);
311 (void) syslog(LOG_ERR,
312 "svc_tli_create: could not do t_sync: %s",
313 errorstr);
314 return (NULL);
315 }
316 if (t_getinfo(fd, &tinfo) == -1) {
317 char errorstr[100];
318
319 __tli_sys_strerror(errorstr, sizeof (errorstr),
320 t_errno, errno);
321 (void) syslog(LOG_ERR, "svc_tli_create: could not get "
322 "transport information: %s", errorstr);
323 return (NULL);
324 }
325 /* Enable options of returning the ip's for udp */
326 if (nconf) {
327 int ret = 0;
328 if (strcmp(nconf->nc_netid, "udp6") == 0) {
329 ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
330 IPV6_RECVPKTINFO, 1);
331 if (ret < 0) {
332 char errorstr[100];
333
334 __tli_sys_strerror(errorstr,
335 sizeof (errorstr), t_errno, errno);
336 (void) syslog(LOG_ERR,
337 "svc_tli_create: "
338 "IPV6_RECVPKTINFO(1): %s",
339 errorstr);
340 return (NULL);
341 }
342 } else if (strcmp(nconf->nc_netid, "udp") == 0) {
343 ret = __rpc_tli_set_options(fd, IPPROTO_IP,
344 IP_RECVDSTADDR, 1);
345 if (ret < 0) {
346 char errorstr[100];
347
348 __tli_sys_strerror(errorstr,
349 sizeof (errorstr), t_errno, errno);
350 (void) syslog(LOG_ERR,
351 "svc_tli_create: "
352 "IP_RECVDSTADDR(1): %s", errorstr);
353 return (NULL);
354 }
355 }
356 }
357 }
358
359 /*
360 * If the fd is unbound, try to bind it.
361 * In any case, try to get its bound info in tres
362 */
363 /* LINTED pointer alignment */
364 tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
365 if (tres == NULL) {
366 (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
367 goto freedata;
368 }
369
370 switch (state) {
371 case T_UNBND:
372 /* If this is a labeled system, then ask for an MLP */
373 if (is_system_labeled() &&
374 (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
375 strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
376 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
377 SO_RECVUCRED, 1);
378 if (mlp_flag)
379 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
380 SO_ANON_MLP, 1);
381 }
382
383 if (bindaddr) {
384 /*
385 * Services that specify a bind address typically
386 * use a fixed service (IP port) so we need to set
387 * SO_REUSEADDR to prevent bind errors on restart.
388 */
389 if (bindaddr->addr.len != 0)
390 (void) __rpc_tli_set_options(fd, SOL_SOCKET,
391 SO_REUSEADDR, 1);
392 if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) {
393 char errorstr[100];
394
395 __tli_sys_strerror(errorstr, sizeof (errorstr),
396 t_errno, errno);
397 (void) syslog(LOG_ERR,
398 "svc_tli_create: could not bind: %s",
399 errorstr);
400 goto freedata;
401 }
402 /*
403 * Should compare the addresses only if addr.len
404 * was non-zero
405 */
406 if (bindaddr->addr.len &&
407 (memcmp(bindaddr->addr.buf, tres->addr.buf,
408 (int)tres->addr.len) != 0)) {
409 (void) syslog(LOG_ERR, "svc_tli_create: could "
410 "not bind to requested address: address "
411 "mismatch");
412 goto freedata;
413 }
414 } else {
415 if (rpc_control(__RPC_SVC_LSTNBKLOG_GET, &tres->qlen)
416 == FALSE) {
417 syslog(LOG_ERR,
418 "svc_tli_create: can't get listen backlog");
419 goto freedata;
420 }
421 tres->addr.len = 0;
422 if (t_bind(fd, tres, tres) == -1) {
423 char errorstr[100];
424
425 __tli_sys_strerror(errorstr, sizeof (errorstr),
426 t_errno, errno);
427 (void) syslog(LOG_ERR,
428 "svc_tli_create: could not bind: %s",
429 errorstr);
430 goto freedata;
431 }
432 }
433
434 /*
435 * If requested, set SO_EXCLBIND on each binding.
436 *
437 * SO_EXCLBIND has the following properties
438 * - an fd bound to port P via IPv4 will prevent an IPv6
439 * bind to port P (and vice versa)
440 * - an fd bound to a wildcard IP address for port P will
441 * prevent a more specific IP address bind to port P
442 * (see {tcp,udp}.c for details)
443 *
444 * We use the latter property to prevent hijacking of RPC
445 * services that reside at non-privileged ports.
446 *
447 * When the bind address is not specified, each bind gets a
448 * new port number, and (for IP transports) we should set
449 * the exclusive flag after every IP bind. That's the
450 * strcmp nc_proto part of the expression below.
451 *
452 * When the bind address IS specified, we need to set the
453 * exclusive flag only after we've bound both IPv6+IPv4,
454 * or the IPv4 bind will fail. Setting the exclusive flag
455 * after the "tcp" or "udp" transport bind does that.
456 * That's the strcmp nc_netid part below.
457 */
458 if (nconf != NULL && ((bindaddr == NULL &&
459 (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
460 strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
461 (strcmp(nconf->nc_netid, "tcp") == 0 ||
462 strcmp(nconf->nc_netid, "udp") == 0))) {
463 bool_t exclbind = FALSE;
464 (void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind);
465 if (exclbind &&
466 __rpc_tli_set_options(fd, SOL_SOCKET,
467 SO_EXCLBIND, 1) < 0) {
468 syslog(LOG_ERR,
469 "svc_tli_create: can't set EXCLBIND [netid='%s']",
470 nconf->nc_netid);
471 goto freedata;
472 }
473 }
474
475 /* Enable options of returning the ip's for udp */
476 if (nconf) {
477 int ret = 0;
478 if (strcmp(nconf->nc_netid, "udp6") == 0) {
479 ret = __rpc_tli_set_options(fd, IPPROTO_IPV6,
480 IPV6_RECVPKTINFO, 1);
481 if (ret < 0) {
482 char errorstr[100];
483
484 __tli_sys_strerror(errorstr,
485 sizeof (errorstr), t_errno, errno);
486 (void) syslog(LOG_ERR,
487 "svc_tli_create: "
488 "IPV6_RECVPKTINFO(2): %s",
489 errorstr);
490 goto freedata;
491 }
492 } else if (strcmp(nconf->nc_netid, "udp") == 0) {
493 ret = __rpc_tli_set_options(fd, IPPROTO_IP,
494 IP_RECVDSTADDR, 1);
495 if (ret < 0) {
496 char errorstr[100];
497
498 __tli_sys_strerror(errorstr,
499 sizeof (errorstr), t_errno, errno);
500 (void) syslog(LOG_ERR,
501 "svc_tli_create: "
502 "IP_RECVDSTADDR(2): %s", errorstr);
503 goto freedata;
504 }
505 }
506 }
507 break;
508
509 case T_IDLE:
510 if (bindaddr) {
511 /* Copy the entire stuff in tres */
512 if (tres->addr.maxlen < bindaddr->addr.len) {
513 (void) syslog(LOG_ERR,
514 "svc_tli_create: illegal netbuf length");
515 goto freedata;
516 }
517 tres->addr.len = bindaddr->addr.len;
518 (void) memcpy(tres->addr.buf, bindaddr->addr.buf,
519 (int)tres->addr.len);
520 } else
521 if (t_getname(fd, &(tres->addr), LOCALNAME) == -1)
522 tres->addr.len = 0;
523 break;
524 case T_INREL:
525 (void) t_rcvrel(fd);
526 (void) t_sndrel(fd);
527 (void) syslog(LOG_ERR, "svc_tli_create: other side wants to "
528 "release connection");
529 goto freedata;
530
531 case T_INCON:
532 /* Do nothing here. Assume this is handled in rendezvous */
533 break;
534 case T_DATAXFER:
535 /*
536 * This takes care of the case where a fd
537 * is passed on which a connection has already
538 * been accepted.
539 */
540 if (t_getname(fd, &(tres->addr), LOCALNAME) == -1)
541 tres->addr.len = 0;
542 break;
543 default:
544 (void) syslog(LOG_ERR,
545 "svc_tli_create: connection in a wierd state (%d)", state);
546 goto freedata;
547 }
548
549 /*
550 * call transport specific function.
551 */
552 switch (tinfo.servtype) {
553 case T_COTS_ORD:
554 case T_COTS:
555 if (state == T_DATAXFER)
556 xprt = svc_fd_create_private(fd, sendsz,
557 recvsz);
558 else
559 xprt = svc_vc_create_private(fd, sendsz,
560 recvsz);
561 if (!nconf || !xprt)
562 break;
563 if ((tinfo.servtype == T_COTS_ORD) &&
564 (state != T_DATAXFER) &&
565 (strcmp(nconf->nc_protofmly, "inet") == 0))
566 (void) __svc_vc_setflag(xprt, TRUE);
567 break;
568 case T_CLTS:
569 xprt = svc_dg_create_private(fd, sendsz, recvsz);
570 break;
571 default:
572 (void) syslog(LOG_ERR,
573 "svc_tli_create: bad service type");
574 goto freedata;
575 }
576 if (xprt == NULL)
577 /*
578 * The error messages here are spitted out by the lower layers:
579 * svc_vc_create(), svc_fd_create() and svc_dg_create().
580 */
581 goto freedata;
582
583 /* fill in the other xprt information */
584
585 /* Assign the local bind address */
586 xprt->xp_ltaddr = tres->addr;
587 /* Fill in type of service */
588 xprt->xp_type = tinfo.servtype;
589 tres->addr.buf = NULL;
590 (void) t_free((char *)tres, T_BIND);
591 tres = NULL;
592
593 xprt->xp_rtaddr.len = 0;
594 xprt->xp_rtaddr.maxlen = __rpc_get_a_size(tinfo.addr);
595
596 /* Allocate space for the remote bind info */
597 if ((xprt->xp_rtaddr.buf = malloc(xprt->xp_rtaddr.maxlen)) == NULL) {
598 (void) syslog(LOG_ERR, "svc_tli_create: No memory!");
599 goto freedata;
600 }
601
602 if (nconf) {
603 xprt->xp_netid = strdup(nconf->nc_netid);
604 if (xprt->xp_netid == NULL) {
605 if (xprt->xp_rtaddr.buf)
606 free(xprt->xp_rtaddr.buf);
607 syslog(LOG_ERR, "svc_tli_create: strdup failed!");
608 goto freedata;
609 }
610 xprt->xp_tp = strdup(nconf->nc_device);
611 if (xprt->xp_tp == NULL) {
612 if (xprt->xp_rtaddr.buf)
613 free(xprt->xp_rtaddr.buf);
614 if (xprt->xp_netid)
615 free(xprt->xp_netid);
616 syslog(LOG_ERR, "svc_tli_create: strdup failed!");
617 goto freedata;
618 }
619 }
620
621 /*
622 * if (madefd && (tinfo.servtype == T_CLTS))
623 * (void) ioctl(fd, I_POP, NULL);
624 */
625 xprt_register(xprt);
626 return (xprt);
627
628 freedata:
629 if (madefd)
630 (void) t_close(fd);
631 if (tres)
632 (void) t_free((char *)tres, T_BIND);
633 if (xprt) {
634 if (!madefd) /* so that svc_destroy doesnt close fd */
635 xprt->xp_fd = RPC_ANYFD;
636 SVC_DESTROY(xprt);
637 }
638 return (NULL);
639 }
640