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