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