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