1 /* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 /* 32 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33 */ 34 35 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 /* 40 * rpc_generic.c, Miscl routines for RPC. 41 * 42 */ 43 44 #include "opt_inet6.h" 45 46 #include <sys/param.h> 47 #include <sys/kernel.h> 48 #include <sys/malloc.h> 49 #include <sys/module.h> 50 #include <sys/proc.h> 51 #include <sys/protosw.h> 52 #include <sys/sbuf.h> 53 #include <sys/systm.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 #include <sys/syslog.h> 57 58 #include <rpc/rpc.h> 59 #include <rpc/nettype.h> 60 61 #include "rpc_com.h" 62 63 struct handle { 64 NCONF_HANDLE *nhandle; 65 int nflag; /* Whether NETPATH or NETCONFIG */ 66 int nettype; 67 }; 68 69 static const struct _rpcnettype { 70 const char *name; 71 const int type; 72 } _rpctypelist[] = { 73 { "netpath", _RPC_NETPATH }, 74 { "visible", _RPC_VISIBLE }, 75 { "circuit_v", _RPC_CIRCUIT_V }, 76 { "datagram_v", _RPC_DATAGRAM_V }, 77 { "circuit_n", _RPC_CIRCUIT_N }, 78 { "datagram_n", _RPC_DATAGRAM_N }, 79 { "tcp", _RPC_TCP }, 80 { "udp", _RPC_UDP }, 81 { 0, _RPC_NONE } 82 }; 83 84 struct netid_af { 85 const char *netid; 86 int af; 87 int protocol; 88 }; 89 90 static const struct netid_af na_cvt[] = { 91 { "udp", AF_INET, IPPROTO_UDP }, 92 { "tcp", AF_INET, IPPROTO_TCP }, 93 #ifdef INET6 94 { "udp6", AF_INET6, IPPROTO_UDP }, 95 { "tcp6", AF_INET6, IPPROTO_TCP }, 96 #endif 97 { "local", AF_LOCAL, 0 } 98 }; 99 100 struct rpc_createerr rpc_createerr; 101 102 /* 103 * Find the appropriate buffer size 104 */ 105 u_int 106 /*ARGSUSED*/ 107 __rpc_get_t_size(int af, int proto, int size) 108 { 109 int maxsize, defsize; 110 111 maxsize = 256 * 1024; /* XXX */ 112 switch (proto) { 113 case IPPROTO_TCP: 114 defsize = 64 * 1024; /* XXX */ 115 break; 116 case IPPROTO_UDP: 117 defsize = UDPMSGSIZE; 118 break; 119 default: 120 defsize = RPC_MAXDATASIZE; 121 break; 122 } 123 if (size == 0) 124 return defsize; 125 126 /* Check whether the value is within the upper max limit */ 127 return (size > maxsize ? (u_int)maxsize : (u_int)size); 128 } 129 130 /* 131 * Find the appropriate address buffer size 132 */ 133 u_int 134 __rpc_get_a_size(af) 135 int af; 136 { 137 switch (af) { 138 case AF_INET: 139 return sizeof (struct sockaddr_in); 140 #ifdef INET6 141 case AF_INET6: 142 return sizeof (struct sockaddr_in6); 143 #endif 144 case AF_LOCAL: 145 return sizeof (struct sockaddr_un); 146 default: 147 break; 148 } 149 return ((u_int)RPC_MAXADDRSIZE); 150 } 151 152 #if 0 153 154 /* 155 * Used to ping the NULL procedure for clnt handle. 156 * Returns NULL if fails, else a non-NULL pointer. 157 */ 158 void * 159 rpc_nullproc(clnt) 160 CLIENT *clnt; 161 { 162 struct timeval TIMEOUT = {25, 0}; 163 164 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 165 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 166 return (NULL); 167 } 168 return ((void *) clnt); 169 } 170 171 #endif 172 173 int 174 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip) 175 { 176 int type, proto; 177 struct sockaddr *sa; 178 sa_family_t family; 179 struct sockopt opt; 180 int error; 181 182 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 183 if (error) 184 return 0; 185 186 sip->si_alen = sa->sa_len; 187 family = sa->sa_family; 188 free(sa, M_SONAME); 189 190 opt.sopt_dir = SOPT_GET; 191 opt.sopt_level = SOL_SOCKET; 192 opt.sopt_name = SO_TYPE; 193 opt.sopt_val = &type; 194 opt.sopt_valsize = sizeof type; 195 opt.sopt_td = NULL; 196 error = sogetopt(so, &opt); 197 if (error) 198 return 0; 199 200 /* XXX */ 201 if (family != AF_LOCAL) { 202 if (type == SOCK_STREAM) 203 proto = IPPROTO_TCP; 204 else if (type == SOCK_DGRAM) 205 proto = IPPROTO_UDP; 206 else 207 return 0; 208 } else 209 proto = 0; 210 211 sip->si_af = family; 212 sip->si_proto = proto; 213 sip->si_socktype = type; 214 215 return 1; 216 } 217 218 /* 219 * Linear search, but the number of entries is small. 220 */ 221 int 222 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 223 { 224 int i; 225 226 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 227 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || ( 228 strcmp(nconf->nc_netid, "unix") == 0 && 229 strcmp(na_cvt[i].netid, "local") == 0)) { 230 sip->si_af = na_cvt[i].af; 231 sip->si_proto = na_cvt[i].protocol; 232 sip->si_socktype = 233 __rpc_seman2socktype((int)nconf->nc_semantics); 234 if (sip->si_socktype == -1) 235 return 0; 236 sip->si_alen = __rpc_get_a_size(sip->si_af); 237 return 1; 238 } 239 240 return 0; 241 } 242 243 struct socket * 244 __rpc_nconf2socket(const struct netconfig *nconf) 245 { 246 struct __rpc_sockinfo si; 247 struct socket *so; 248 int error; 249 250 if (!__rpc_nconf2sockinfo(nconf, &si)) 251 return 0; 252 253 so = NULL; 254 error = socreate(si.si_af, &so, si.si_socktype, si.si_proto, 255 curthread->td_ucred, curthread); 256 257 if (error) 258 return NULL; 259 else 260 return so; 261 } 262 263 char * 264 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 265 { 266 struct __rpc_sockinfo si; 267 268 if (!__rpc_nconf2sockinfo(nconf, &si)) 269 return NULL; 270 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 271 } 272 273 struct netbuf * 274 uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 275 { 276 struct __rpc_sockinfo si; 277 278 if (!__rpc_nconf2sockinfo(nconf, &si)) 279 return NULL; 280 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 281 } 282 283 char * 284 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 285 { 286 char *ret; 287 struct sbuf sb; 288 struct sockaddr_in *sin; 289 struct sockaddr_un *sun; 290 char namebuf[INET_ADDRSTRLEN]; 291 #ifdef INET6 292 struct sockaddr_in6 *sin6; 293 char namebuf6[INET6_ADDRSTRLEN]; 294 #endif 295 u_int16_t port; 296 297 sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND); 298 299 switch (af) { 300 case AF_INET: 301 sin = nbuf->buf; 302 if (__rpc_inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 303 == NULL) 304 return NULL; 305 port = ntohs(sin->sin_port); 306 if (sbuf_printf(&sb, "%s.%u.%u", namebuf, 307 ((uint32_t)port) >> 8, 308 port & 0xff) < 0) 309 return NULL; 310 break; 311 #ifdef INET6 312 case AF_INET6: 313 sin6 = nbuf->buf; 314 if (__rpc_inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 315 == NULL) 316 return NULL; 317 port = ntohs(sin6->sin6_port); 318 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6, 319 ((uint32_t)port) >> 8, 320 port & 0xff) < 0) 321 return NULL; 322 break; 323 #endif 324 case AF_LOCAL: 325 sun = nbuf->buf; 326 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len - 327 offsetof(struct sockaddr_un, sun_path)), 328 sun->sun_path) < 0) 329 return (NULL); 330 break; 331 default: 332 return NULL; 333 } 334 335 sbuf_finish(&sb); 336 ret = strdup(sbuf_data(&sb), M_RPC); 337 sbuf_delete(&sb); 338 339 return ret; 340 } 341 342 struct netbuf * 343 __rpc_uaddr2taddr_af(int af, const char *uaddr) 344 { 345 struct netbuf *ret = NULL; 346 char *addrstr, *p; 347 unsigned port, portlo, porthi; 348 struct sockaddr_in *sin; 349 #ifdef INET6 350 struct sockaddr_in6 *sin6; 351 #endif 352 struct sockaddr_un *sun; 353 354 port = 0; 355 sin = NULL; 356 addrstr = strdup(uaddr, M_RPC); 357 if (addrstr == NULL) 358 return NULL; 359 360 /* 361 * AF_LOCAL addresses are expected to be absolute 362 * pathnames, anything else will be AF_INET or AF_INET6. 363 */ 364 if (*addrstr != '/') { 365 p = strrchr(addrstr, '.'); 366 if (p == NULL) 367 goto out; 368 portlo = (unsigned)strtol(p + 1, NULL, 10); 369 *p = '\0'; 370 371 p = strrchr(addrstr, '.'); 372 if (p == NULL) 373 goto out; 374 porthi = (unsigned)strtol(p + 1, NULL, 10); 375 *p = '\0'; 376 port = (porthi << 8) | portlo; 377 } 378 379 ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK); 380 if (ret == NULL) 381 goto out; 382 383 switch (af) { 384 case AF_INET: 385 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC, 386 M_WAITOK); 387 if (sin == NULL) 388 goto out; 389 memset(sin, 0, sizeof *sin); 390 sin->sin_family = AF_INET; 391 sin->sin_port = htons(port); 392 if (__rpc_inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 393 free(sin, M_RPC); 394 free(ret, M_RPC); 395 ret = NULL; 396 goto out; 397 } 398 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 399 ret->buf = sin; 400 break; 401 #ifdef INET6 402 case AF_INET6: 403 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC, 404 M_WAITOK); 405 if (sin6 == NULL) 406 goto out; 407 memset(sin6, 0, sizeof *sin6); 408 sin6->sin6_family = AF_INET6; 409 sin6->sin6_port = htons(port); 410 if (__rpc_inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 411 free(sin6, M_RPC); 412 free(ret, M_RPC); 413 ret = NULL; 414 goto out; 415 } 416 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 417 ret->buf = sin6; 418 break; 419 #endif 420 case AF_LOCAL: 421 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC, 422 M_WAITOK); 423 if (sun == NULL) 424 goto out; 425 memset(sun, 0, sizeof *sun); 426 sun->sun_family = AF_LOCAL; 427 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 428 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 429 ret->buf = sun; 430 break; 431 default: 432 break; 433 } 434 out: 435 free(addrstr, M_RPC); 436 return ret; 437 } 438 439 int 440 __rpc_seman2socktype(int semantics) 441 { 442 switch (semantics) { 443 case NC_TPI_CLTS: 444 return SOCK_DGRAM; 445 case NC_TPI_COTS_ORD: 446 return SOCK_STREAM; 447 case NC_TPI_RAW: 448 return SOCK_RAW; 449 default: 450 break; 451 } 452 453 return -1; 454 } 455 456 int 457 __rpc_socktype2seman(int socktype) 458 { 459 switch (socktype) { 460 case SOCK_DGRAM: 461 return NC_TPI_CLTS; 462 case SOCK_STREAM: 463 return NC_TPI_COTS_ORD; 464 case SOCK_RAW: 465 return NC_TPI_RAW; 466 default: 467 break; 468 } 469 470 return -1; 471 } 472 473 /* 474 * Returns the type of the network as defined in <rpc/nettype.h> 475 * If nettype is NULL, it defaults to NETPATH. 476 */ 477 static int 478 getnettype(const char *nettype) 479 { 480 int i; 481 482 if ((nettype == NULL) || (nettype[0] == 0)) { 483 return (_RPC_NETPATH); /* Default */ 484 } 485 486 #if 0 487 nettype = strlocase(nettype); 488 #endif 489 for (i = 0; _rpctypelist[i].name; i++) 490 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 491 return (_rpctypelist[i].type); 492 } 493 return (_rpctypelist[i].type); 494 } 495 496 /* 497 * For the given nettype (tcp or udp only), return the first structure found. 498 * This should be freed by calling freenetconfigent() 499 */ 500 struct netconfig * 501 __rpc_getconfip(const char *nettype) 502 { 503 char *netid; 504 static char *netid_tcp = (char *) NULL; 505 static char *netid_udp = (char *) NULL; 506 struct netconfig *dummy; 507 508 if (!netid_udp && !netid_tcp) { 509 struct netconfig *nconf; 510 void *confighandle; 511 512 if (!(confighandle = setnetconfig())) { 513 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 514 return (NULL); 515 } 516 while ((nconf = getnetconfig(confighandle)) != NULL) { 517 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 518 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 519 netid_tcp = strdup(nconf->nc_netid, 520 M_RPC); 521 } else 522 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 523 netid_udp = strdup(nconf->nc_netid, 524 M_RPC); 525 } 526 } 527 } 528 endnetconfig(confighandle); 529 } 530 if (strcmp(nettype, "udp") == 0) 531 netid = netid_udp; 532 else if (strcmp(nettype, "tcp") == 0) 533 netid = netid_tcp; 534 else { 535 return (NULL); 536 } 537 if ((netid == NULL) || (netid[0] == 0)) { 538 return (NULL); 539 } 540 dummy = getnetconfigent(netid); 541 return (dummy); 542 } 543 544 /* 545 * Returns the type of the nettype, which should then be used with 546 * __rpc_getconf(). 547 * 548 * For simplicity in the kernel, we don't support the NETPATH 549 * environment variable. We behave as userland would then NETPATH is 550 * unset, i.e. iterate over all visible entries in netconfig. 551 */ 552 void * 553 __rpc_setconf(nettype) 554 const char *nettype; 555 { 556 struct handle *handle; 557 558 handle = (struct handle *) malloc(sizeof (struct handle), 559 M_RPC, M_WAITOK); 560 switch (handle->nettype = getnettype(nettype)) { 561 case _RPC_NETPATH: 562 case _RPC_CIRCUIT_N: 563 case _RPC_DATAGRAM_N: 564 if (!(handle->nhandle = setnetconfig())) 565 goto failed; 566 handle->nflag = TRUE; 567 break; 568 case _RPC_VISIBLE: 569 case _RPC_CIRCUIT_V: 570 case _RPC_DATAGRAM_V: 571 case _RPC_TCP: 572 case _RPC_UDP: 573 if (!(handle->nhandle = setnetconfig())) { 574 log(LOG_ERR, "rpc: failed to open " NETCONFIG); 575 goto failed; 576 } 577 handle->nflag = FALSE; 578 break; 579 default: 580 goto failed; 581 } 582 583 return (handle); 584 585 failed: 586 free(handle, M_RPC); 587 return (NULL); 588 } 589 590 /* 591 * Returns the next netconfig struct for the given "net" type. 592 * __rpc_setconf() should have been called previously. 593 */ 594 struct netconfig * 595 __rpc_getconf(void *vhandle) 596 { 597 struct handle *handle; 598 struct netconfig *nconf; 599 600 handle = (struct handle *)vhandle; 601 if (handle == NULL) { 602 return (NULL); 603 } 604 for (;;) { 605 if (handle->nflag) { 606 nconf = getnetconfig(handle->nhandle); 607 if (nconf && !(nconf->nc_flag & NC_VISIBLE)) 608 continue; 609 } else { 610 nconf = getnetconfig(handle->nhandle); 611 } 612 if (nconf == NULL) 613 break; 614 if ((nconf->nc_semantics != NC_TPI_CLTS) && 615 (nconf->nc_semantics != NC_TPI_COTS) && 616 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 617 continue; 618 switch (handle->nettype) { 619 case _RPC_VISIBLE: 620 if (!(nconf->nc_flag & NC_VISIBLE)) 621 continue; 622 /* FALLTHROUGH */ 623 case _RPC_NETPATH: /* Be happy */ 624 break; 625 case _RPC_CIRCUIT_V: 626 if (!(nconf->nc_flag & NC_VISIBLE)) 627 continue; 628 /* FALLTHROUGH */ 629 case _RPC_CIRCUIT_N: 630 if ((nconf->nc_semantics != NC_TPI_COTS) && 631 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 632 continue; 633 break; 634 case _RPC_DATAGRAM_V: 635 if (!(nconf->nc_flag & NC_VISIBLE)) 636 continue; 637 /* FALLTHROUGH */ 638 case _RPC_DATAGRAM_N: 639 if (nconf->nc_semantics != NC_TPI_CLTS) 640 continue; 641 break; 642 case _RPC_TCP: 643 if (((nconf->nc_semantics != NC_TPI_COTS) && 644 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 645 (strcmp(nconf->nc_protofmly, NC_INET) 646 #ifdef INET6 647 && strcmp(nconf->nc_protofmly, NC_INET6)) 648 #else 649 ) 650 #endif 651 || 652 strcmp(nconf->nc_proto, NC_TCP)) 653 continue; 654 break; 655 case _RPC_UDP: 656 if ((nconf->nc_semantics != NC_TPI_CLTS) || 657 (strcmp(nconf->nc_protofmly, NC_INET) 658 #ifdef INET6 659 && strcmp(nconf->nc_protofmly, NC_INET6)) 660 #else 661 ) 662 #endif 663 || 664 strcmp(nconf->nc_proto, NC_UDP)) 665 continue; 666 break; 667 } 668 break; 669 } 670 return (nconf); 671 } 672 673 void 674 __rpc_endconf(vhandle) 675 void * vhandle; 676 { 677 struct handle *handle; 678 679 handle = (struct handle *) vhandle; 680 if (handle == NULL) { 681 return; 682 } 683 endnetconfig(handle->nhandle); 684 free(handle, M_RPC); 685 } 686 687 int 688 __rpc_sockisbound(struct socket *so) 689 { 690 struct sockaddr *sa; 691 int error, bound; 692 693 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 694 if (error) 695 return (0); 696 697 switch (sa->sa_family) { 698 case AF_INET: 699 bound = (((struct sockaddr_in *) sa)->sin_port != 0); 700 break; 701 #ifdef INET6 702 case AF_INET6: 703 bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0); 704 break; 705 #endif 706 case AF_LOCAL: 707 /* XXX check this */ 708 bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0'); 709 break; 710 default: 711 bound = FALSE; 712 break; 713 } 714 715 free(sa, M_SONAME); 716 717 return bound; 718 } 719 720 /* 721 * Kernel module glue 722 */ 723 static int 724 krpc_modevent(module_t mod, int type, void *data) 725 { 726 727 return (0); 728 } 729 static moduledata_t krpc_mod = { 730 "krpc", 731 krpc_modevent, 732 NULL, 733 }; 734 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY); 735 736 /* So that loader and kldload(2) can find us, wherever we are.. */ 737 MODULE_VERSION(krpc, 1); 738