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 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 108 __svc_free_xprtlist(void) 109 { 110 __svc_free_xlist(&_svc_xprtlist, &xprtlist_lock); 111 } 112 113 int 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 * 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 * 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 * 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 * 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 * 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 }