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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains the routines that maintain a linked list of known 31 * program to udp port mappings. There are three static members initialized 32 * by default, one for the portmapper itself (of course), one for rpcbind, 33 * and one for nfs. If a program number is not in the list, then routines 34 * in this file contact the portmapper on the server, and dynamically add 35 * new members to this list. 36 * 37 * This file also contains bpmap_rmtcall() - which lets one get the port 38 * number AND run the rpc call in one step. Only the server that successfully 39 * completes the rpc call will return a result. 40 * 41 * NOTE: Because we will end up caching the port entries we need 42 * before the kernel begins running, we can use dynamic allocation here. 43 * boot_memfree() calls bpmap_memfree() to free up any dynamically 44 * allocated entries when the boot program has finished its job. 45 */ 46 47 #include <sys/types.h> 48 #include <rpc/types.h> 49 #include <sys/errno.h> 50 #include <sys/time.h> 51 #include <sys/socket.h> 52 #include <net/if.h> 53 #include <netinet/in.h> 54 #include <netinet/if_ether.h> 55 #include <rpc/xdr.h> 56 #include <rpc/auth.h> 57 #include <sys/t_lock.h> 58 #include "clnt.h" 59 #include <rpc/pmap_prot.h> 60 #include <rpc/pmap_rmt.h> 61 #include <rpc/rpc.h> 62 #include "brpc.h" 63 #include "pmap.h" 64 #include "nfs_inet.h" 65 #include <rpcsvc/nfs_prot.h> 66 #include <rpc/rpcb_prot.h> 67 #include <sys/salib.h> 68 #include "socket_inet.h" 69 #include <sys/promif.h> 70 #include <sys/bootdebug.h> 71 72 /* portmap structure */ 73 #define PMAP_STATIC (3) /* last statically allocated list entry */ 74 struct pmaplist pre_init[PMAP_STATIC + 1] = { 75 { {PMAPPROG, PMAPVERS, IPPROTO_UDP, PMAPPORT}, &pre_init[1] }, 76 /* SVR4 rpcbind listens to old portmapper port */ 77 { {RPCBPROG, RPCBVERS, IPPROTO_UDP, PMAPPORT}, &pre_init[2] }, 78 { {NFS_PROGRAM, NFS_VERSION, IPPROTO_UDP, NFS_PORT}, &pre_init[3] }, 79 { {NFS_PROGRAM, NFS_V3, IPPROTO_UDP, NFS_PORT}, NULL } 80 }; 81 82 struct pmaplist *map_head = &pre_init[0]; 83 struct pmaplist *map_tail = &pre_init[PMAP_STATIC]; 84 85 #define dprintf if (boothowto & RB_DEBUG) printf 86 87 /* 88 * bpmap_addport: adds a new entry on to the end of the pmap cache. 89 * Items are kept in host order. 90 */ 91 static void 92 bpmap_addport(rpcprog_t prog, rpcvers_t vers, rpcport_t port) 93 { 94 struct pmaplist *newp; 95 96 /* allocate new pmaplist */ 97 newp = (struct pmaplist *)bkmem_alloc(sizeof (struct pmaplist)); 98 99 if (newp == NULL) 100 return; /* not fatal here, we'll just throw out the entry */ 101 102 newp->pml_map.pm_prog = prog; 103 newp->pml_map.pm_vers = vers; 104 newp->pml_map.pm_prot = (rpcprot_t)IPPROTO_UDP; 105 newp->pml_map.pm_port = port; 106 107 map_tail->pml_next = newp; 108 newp->pml_next = NULL; 109 map_tail = newp; 110 } 111 112 /* 113 * bpmap_delport: deletes an existing entry from the list. Caution - don't 114 * call this function to delete statically allocated entries. Why would 115 * you want to, anyway? Only IPPROTO_UDP is supported, of course. 116 */ 117 static void 118 bpmap_delport(rpcprog_t prog, rpcvers_t vers) 119 { 120 struct pmaplist *tmp, *prev; 121 122 prev = map_head; 123 for (tmp = map_head; tmp != NULL; tmp = tmp->pml_next) { 124 if ((tmp->pml_map.pm_prog == prog) && 125 (tmp->pml_map.pm_vers == vers)) { 126 if (tmp == map_head) 127 map_head = tmp->pml_next; /* new head */ 128 else if (tmp == map_tail) { 129 map_tail = prev; /* new tail */ 130 map_tail->pml_next = NULL; 131 } else { 132 /* internal delete */ 133 prev->pml_next = tmp->pml_next; 134 } 135 #ifdef DEBUG 136 printf("bpmap_delport: prog: %x, vers: %x\n", prog, 137 vers); 138 #endif /* DEBUG */ 139 bkmem_free((caddr_t)tmp, sizeof (struct pmaplist)); 140 break; 141 } else 142 prev = tmp; 143 } 144 } 145 146 /* 147 * Modified strtol(3). 148 */ 149 static int 150 strtoi(char *str, char **ptr) 151 { 152 int c, val; 153 154 for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) { 155 val *= 10; 156 val += c - '0'; 157 } 158 *ptr = str; 159 return (val); 160 } 161 162 /* 163 * (from dlboot_inet.c) (kernel) 164 * Convert a port number from a sockaddr_in expressed 165 * in universal address format. 166 */ 167 static int 168 uaddr2port(char *addr) 169 { 170 int p1, p2; 171 char *next; 172 173 /* 174 * A struct sockaddr_in expressed in universal address 175 * format looks like: 176 * 177 * "IP.IP.IP.IP.PORT[top byte].PORT[bot. byte]" 178 * 179 * Where each component expresses as a charactor, 180 * the corresponding part of the IP address 181 * and port number. 182 * Thus 127.0.0.1, port 2345 looks like: 183 * 184 * 49 50 55 46 48 46 48 46 49 46 57 46 52 49 185 * 1 2 7 . 0 . 0 . 1 . 9 . 4 1 186 * 187 * 2345 = 929base16 = 9.32+9 = 9.41 188 */ 189 (void) strtoi(addr, &next); 190 (void) strtoi(next, &next); 191 (void) strtoi(next, &next); 192 (void) strtoi(next, &next); 193 p1 = strtoi(next, &next); 194 p2 = strtoi(next, &next); 195 196 return ((p1 << 8) + p2); 197 } 198 199 /* 200 * Xdr routines used for calling portmapper/rpcbind. 201 */ 202 203 bool_t 204 xdr_pmap(XDR *xdrs, struct pmap *regs) 205 { 206 if (xdr_rpcprog(xdrs, ®s->pm_prog) && 207 xdr_rpcvers(xdrs, ®s->pm_vers) && 208 xdr_rpcprot(xdrs, ®s->pm_prot)) 209 return (xdr_rpcprot(xdrs, ®s->pm_port)); 210 return (FALSE); 211 } 212 213 bool_t 214 xdr_rpcb(XDR *xdrs, RPCB *objp) 215 { 216 if (!xdr_rpcprog(xdrs, &objp->r_prog)) 217 return (FALSE); 218 if (!xdr_rpcvers(xdrs, &objp->r_vers)) 219 return (FALSE); 220 if (!xdr_string(xdrs, &objp->r_netid, ~0)) 221 return (FALSE); 222 if (!xdr_string(xdrs, &objp->r_addr, ~0)) 223 return (FALSE); 224 if (!xdr_string(xdrs, &objp->r_owner, ~0)) 225 return (FALSE); 226 return (TRUE); 227 } 228 229 /* 230 * XDR remote call arguments 231 * written for XDR_ENCODE direction only 232 */ 233 bool_t 234 xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap) 235 { 236 uint_t lenposition, argposition, position; 237 238 if (xdr_rpcprog(xdrs, &(cap->prog)) && 239 xdr_rpcvers(xdrs, &(cap->vers)) && 240 xdr_rpcproc(xdrs, &(cap->proc))) { 241 lenposition = XDR_GETPOS(xdrs); 242 if (!xdr_u_int(xdrs, &(cap->arglen))) 243 return (FALSE); 244 argposition = XDR_GETPOS(xdrs); 245 if (!(*(cap->xdr_args))(xdrs, cap->args_ptr)) 246 return (FALSE); 247 position = XDR_GETPOS(xdrs); 248 cap->arglen = position - argposition; 249 XDR_SETPOS(xdrs, lenposition); 250 if (!xdr_u_int(xdrs, &(cap->arglen))) 251 return (FALSE); 252 XDR_SETPOS(xdrs, position); 253 return (TRUE); 254 } 255 return (FALSE); 256 } 257 258 /* 259 * XDR remote call results 260 * written for XDR_DECODE direction only 261 */ 262 bool_t 263 xdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp) 264 { 265 caddr_t port_ptr; 266 267 port_ptr = (caddr_t)crp->port_ptr; 268 if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) && 269 xdr_u_int(xdrs, &crp->resultslen)) { 270 crp->port_ptr = (rpcport_t *)port_ptr; 271 return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); 272 } 273 return (FALSE); 274 } 275 276 /* 277 * XDR remote call arguments 278 * written for XDR_ENCODE direction only 279 */ 280 bool_t 281 xdr_rpcb_rmtcallargs(XDR *xdrs, struct rpcb_rmtcallargs *objp) 282 { 283 uint_t lenposition, argposition, position; 284 285 if (!xdr_rpcprog(xdrs, &objp->prog)) 286 return (FALSE); 287 if (!xdr_rpcvers(xdrs, &objp->vers)) 288 return (FALSE); 289 if (!xdr_rpcproc(xdrs, &objp->proc)) 290 return (FALSE); 291 /* 292 * All the jugglery for just getting the size of the arguments 293 */ 294 lenposition = XDR_GETPOS(xdrs); 295 if (!xdr_u_int(xdrs, &(objp->arglen))) 296 return (FALSE); 297 argposition = XDR_GETPOS(xdrs); 298 if (!(*(objp->xdr_args))(xdrs, objp->args_ptr)) 299 return (FALSE); 300 position = XDR_GETPOS(xdrs); 301 objp->arglen = position - argposition; 302 XDR_SETPOS(xdrs, lenposition); 303 if (!xdr_u_int(xdrs, &(objp->arglen))) 304 return (FALSE); 305 XDR_SETPOS(xdrs, position); 306 return (TRUE); 307 } 308 309 /* 310 * XDR remote call results 311 * written for XDR_DECODE direction only 312 */ 313 bool_t 314 xdr_rpcb_rmtcallres(XDR *xdrs, struct rpcb_rmtcallres *objp) 315 { 316 if (!xdr_string(xdrs, &objp->addr_ptr, ~0)) 317 return (FALSE); 318 if (!xdr_u_int(xdrs, &objp->resultslen)) 319 return (FALSE); 320 return ((*(objp->xdr_results))(xdrs, objp->results_ptr)); 321 } 322 323 /* 324 * bpmap_rmtcall: does PMAPPROC_CALLIT broadcasts w/ rpc_call requests. 325 * Lets one do a PMAPGETPORT/RPC PROC call in one easy step. sockaddr_in args 326 * are taken as network order. 327 * 328 * Code adapted from bpmap_rmtcall() in dlboot_inet.c (kernel) 329 */ 330 /*ARGSUSED*/ 331 enum clnt_stat 332 bpmap_rmtcall( 333 rpcprog_t prog, /* rpc program number to call. */ 334 rpcvers_t vers, /* rpc program version */ 335 rpcproc_t proc, /* rpc procedure to call */ 336 xdrproc_t in_xdr, /* routine to serialize arguments */ 337 caddr_t args, /* arg vector for remote call */ 338 xdrproc_t out_xdr, /* routine to deserialize results */ 339 caddr_t ret, /* addr of buf to place results in */ 340 int rexmit, /* retransmission interval (secs) */ 341 int wait, /* how long (secs) to wait for a resp */ 342 struct sockaddr_in *to, /* destination */ 343 struct sockaddr_in *from, /* filled in w/ responder's port/addr */ 344 uint_t auth) /* type of authentication wanted. */ 345 { 346 enum clnt_stat status; /* rpc_call status */ 347 rpcport_t port = 0; /* returned port # */ 348 struct rmtcallargs pmap_a; /* args for pmap call */ 349 struct rmtcallres pmap_r; /* results from pmap call */ 350 struct rpcb_rmtcallargs rpcb_a; /* args for rpcb call */ 351 struct rpcb_rmtcallres rpcb_r; /* results from rpcb call */ 352 char ua[UA_SIZE]; /* universal addr buffer */ 353 354 /* initialize pmap */ 355 pmap_a.prog = prog; 356 pmap_a.vers = vers; 357 pmap_a.proc = proc; 358 pmap_a.args_ptr = args; 359 pmap_a.xdr_args = in_xdr; 360 pmap_r.port_ptr = &port; 361 pmap_r.results_ptr = ret; 362 pmap_r.xdr_results = out_xdr; 363 364 status = brpc_call((rpcprog_t)PMAPPROG, (rpcvers_t)PMAPVERS, 365 (rpcproc_t)PMAPPROC_CALLIT, xdr_rmtcall_args, (caddr_t)&pmap_a, 366 xdr_rmtcallres, (caddr_t)&pmap_r, rexmit, wait, to, from, 367 AUTH_NONE); 368 if (status != RPC_PROGUNAVAIL) { 369 if (status == RPC_SUCCESS) { 370 /* delete old port mapping, if it exists */ 371 bpmap_delport(prog, vers); 372 373 /* save the new port mapping */ 374 bpmap_addport(prog, vers, port); 375 } 376 return (status); 377 } 378 379 /* 380 * PMAP is unavailable. Maybe there's a SVR4 machine, with rpcbind. 381 */ 382 bzero(ua, sizeof (ua)); 383 384 /* initialize rpcb */ 385 rpcb_a.prog = prog; 386 rpcb_a.vers = vers; 387 rpcb_a.proc = proc; 388 rpcb_a.args_ptr = args; 389 rpcb_a.xdr_args = in_xdr; 390 rpcb_r.addr_ptr = ua; 391 rpcb_r.results_ptr = ret; 392 rpcb_r.xdr_results = out_xdr; 393 394 status = brpc_call((rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS, 395 (rpcproc_t)RPCBPROC_CALLIT, xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_a, 396 xdr_rpcb_rmtcallres, (caddr_t)&rpcb_r, rexmit, wait, to, from, 397 AUTH_NONE); 398 if (status == RPC_SUCCESS) { 399 /* delete old port mapping, if it exists */ 400 bpmap_delport(prog, vers); 401 402 /* save the new port mapping */ 403 port = ntohs(uaddr2port(ua)); 404 bpmap_addport(prog, vers, port); 405 } 406 return (status); 407 } 408 409 /* 410 * bpmap_getport: Queries current list of cached pmap_list entries, 411 * returns the port number of the entry found. If the port number 412 * is not cached, then getport makes a rpc call first to the portmapper, 413 * and then to rpcbind (SVR4) if the portmapper does not respond. The 414 * returned port is then added to the cache, and the port number is 415 * returned. If both portmapper and rpc bind fail to give us the necessary 416 * port, we return 0 to signal we hit an error, and set rpc_stat to 417 * the appropriate RPC error code. Only IPPROTO_UDP protocol is supported. 418 * 419 * Port and sockaddr_in arguments taken in network order. rpcport_t is returned 420 * in host order. 421 */ 422 rpcport_t 423 bpmap_getport(rpcprog_t prog, rpcvers_t vers, enum clnt_stat *rpc_stat, 424 struct sockaddr_in *to, struct sockaddr_in *from) 425 { 426 struct pmaplist *walk; 427 struct pmap pmap_send; /* portmap */ 428 in_port_t pmap_port; 429 rpcport_t dport; 430 431 #ifdef DEBUG 432 printf("bpmap_getport: called with: prog: %d, vers: %d\n", prog, vers); 433 #endif /* DEBUG */ 434 for (walk = map_head; walk != 0; walk = walk->pml_next) { 435 if ((walk->pml_map.pm_prog == prog) && 436 (walk->pml_map.pm_vers == vers) && 437 (walk->pml_map.pm_prot == (rpcprot_t)IPPROTO_UDP)) { 438 #ifdef DEBUG 439 printf("bpmap_getport: Found in cache. returning: %d\n", 440 walk->pml_map.pm_port); 441 #endif /* DEBUG */ 442 return (walk->pml_map.pm_port); 443 } 444 } 445 446 /* 447 * Not in the cache. First try the portmapper (SunOS server?) and 448 * if that fails, try rpcbind (SVR4 server). 449 */ 450 pmap_send.pm_prog = prog; 451 pmap_send.pm_vers = vers; 452 pmap_send.pm_prot = (rpcprot_t)IPPROTO_UDP; 453 pmap_send.pm_port = 0; /* what we're after */ 454 455 *rpc_stat = brpc_call(PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 456 xdr_pmap, (caddr_t)&pmap_send, xdr_u_short, 457 (caddr_t)&pmap_port, 0, 0, to, from, AUTH_NONE); 458 459 if (*rpc_stat == RPC_PROGUNAVAIL) { 460 /* 461 * The portmapper isn't available. Try rpcbind. 462 * Maybe the server is a SVR4 server. 463 */ 464 char *ua; /* universal address */ 465 char ua_buf[UA_SIZE]; /* and its buffer */ 466 RPCB rpcb_send; 467 468 rpcb_send.r_prog = prog; 469 rpcb_send.r_vers = vers; 470 rpcb_send.r_netid = NULL; 471 rpcb_send.r_addr = NULL; 472 rpcb_send.r_owner = NULL; 473 474 bzero(ua_buf, UA_SIZE); 475 ua = ua_buf; 476 477 /* 478 * Again, default # of retries. xdr_wrapstring() 479 * wants a char **. 480 */ 481 *rpc_stat = brpc_call(RPCBPROG, RPCBVERS, RPCBPROC_GETADDR, 482 xdr_rpcb, (caddr_t)&rpcb_send, xdr_wrapstring, 483 (char *)&ua, 0, 0, to, from, AUTH_NONE); 484 485 if (*rpc_stat == RPC_SUCCESS) { 486 if (ua[0] != '\0') 487 dport = ntohs(uaddr2port(ua)); 488 else 489 return (0); /* Address unknown */ 490 } 491 } else { 492 /* 493 * Why are rpcport_t's uint32_t? port numbers are uint16_t 494 * for ipv4 AND ipv6.... XXXX 495 */ 496 dport = (rpcport_t)pmap_port; 497 } 498 499 if (*rpc_stat != RPC_SUCCESS) { 500 dprintf("pmap_getport: Failed getting port.\n"); 501 return (0); /* we failed. */ 502 } 503 504 #ifdef DEBUG 505 printf("bpmap_getport: prog: %d, vers: %d; returning port: %d.\n", 506 prog, vers, dport); 507 #endif /* DEBUG */ 508 509 bpmap_addport(prog, vers, dport); 510 511 return (dport); 512 } 513 514 /* 515 * bpmap_memfree: frees up any dynamically allocated entries. 516 */ 517 void 518 bpmap_memfree(void) 519 { 520 struct pmaplist *current, *tmp; 521 522 if (map_tail == &pre_init[PMAP_STATIC]) 523 return; /* no dynamic entries */ 524 525 /* free from head of the list to the tail. */ 526 current = pre_init[PMAP_STATIC].pml_next; 527 while (current != NULL) { 528 tmp = current->pml_next; 529 bkmem_free((caddr_t)current, sizeof (struct pmaplist)); 530 current = tmp; 531 } 532 } 533