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